summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules2
-rw-r--r--HACKING19
-rw-r--r--Makefile.objs1
-rw-r--r--QMP/qmp-events.txt17
-rw-r--r--arch_init.c143
-rw-r--r--async.c33
-rw-r--r--block-migration.c32
-rw-r--r--block.c29
-rw-r--r--block/gluster.c45
-rw-r--r--block/iscsi.c104
-rw-r--r--block/raw.c14
-rw-r--r--block/vvfat.c25
-rw-r--r--bsd-user/main.c10
-rwxr-xr-xconfigure117
-rw-r--r--cpu-exec.c10
-rw-r--r--cpus.c44
-rw-r--r--default-configs/alpha-softmmu.mak1
-rw-r--r--default-configs/mips-softmmu.mak2
-rw-r--r--default-configs/mips64-softmmu.mak2
-rw-r--r--default-configs/mips64el-softmmu.mak2
-rw-r--r--default-configs/mipsel-softmmu.mak2
-rw-r--r--default-configs/ppc-softmmu.mak1
-rw-r--r--default-configs/ppc64-softmmu.mak7
-rw-r--r--default-configs/ppcemb-softmmu.mak1
-rw-r--r--default-configs/sh4-softmmu.mak9
-rw-r--r--default-configs/sh4eb-softmmu.mak9
-rw-r--r--default-configs/sparc64-softmmu.mak1
-rw-r--r--device_tree.c33
-rw-r--r--disas.c4
-rw-r--r--docs/rdma.txt51
-rw-r--r--exec.c51
-rw-r--r--gdbstub.c266
-rw-r--r--hmp.c4
-rw-r--r--hw/acpi/piix4.c63
-rw-r--r--hw/alpha/typhoon.c2
-rw-r--r--hw/arm/boot.c48
-rw-r--r--hw/arm/vexpress.c128
-rw-r--r--hw/block/dataplane/virtio-blk.c2
-rw-r--r--hw/block/fdc.c126
-rw-r--r--hw/block/m25p80.c12
-rw-r--r--hw/block/pflash_cfi01.c33
-rw-r--r--hw/block/pflash_cfi02.c36
-rw-r--r--hw/core/loader.c84
-rw-r--r--hw/display/vmware_vga.c36
-rw-r--r--hw/i2c/exynos4210_i2c.c2
-rw-r--r--hw/i386/kvm/clock.c18
-rw-r--r--hw/i386/kvmvapic.c90
-rw-r--r--hw/i386/pc.c2
-rw-r--r--hw/i386/pc_q35.c4
-rw-r--r--hw/ide/ahci.c39
-rw-r--r--hw/ide/ahci.h10
-rw-r--r--hw/ide/ich.c32
-rw-r--r--hw/intc/ioapic_common.c12
-rw-r--r--hw/isa/Makefile.objs1
-rw-r--r--hw/isa/isa-bus.c8
-rw-r--r--hw/isa/isa_mmio.c81
-rw-r--r--hw/mips/gt64xxx_pci.c3
-rw-r--r--hw/mips/mips_fulong2e.c3
-rw-r--r--hw/mips/mips_jazz.c8
-rw-r--r--hw/mips/mips_malta.c3
-rw-r--r--hw/mips/mips_mipssim.c8
-rw-r--r--hw/mips/mips_r4k.c6
-rw-r--r--hw/misc/ivshmem.c59
-rw-r--r--hw/misc/pc-testdev.c28
-rw-r--r--hw/misc/pci-testdev.c24
-rw-r--r--hw/misc/slavio_misc.c2
-rw-r--r--hw/misc/vfio.c782
-rw-r--r--hw/net/e1000.c53
-rw-r--r--hw/net/milkymist-minimac2.c2
-rw-r--r--hw/net/pcnet-pci.c21
-rw-r--r--hw/net/rtl8139.c114
-rw-r--r--hw/net/virtio-net.c133
-rw-r--r--hw/nvram/fw_cfg.c42
-rw-r--r--hw/openrisc/openrisc_sim.c6
-rw-r--r--hw/pci-bridge/i82801b11.c2
-rw-r--r--hw/pci-host/apb.c101
-rw-r--r--hw/pci-host/bonito.c25
-rw-r--r--hw/pci-host/piix.c54
-rw-r--r--hw/pci-host/q35.c68
-rw-r--r--hw/pci/pci-hotplug-old.c2
-rw-r--r--hw/pci/pci.c5
-rw-r--r--hw/pci/pci_bridge.c2
-rw-r--r--hw/ppc/mac_newworld.c5
-rw-r--r--hw/ppc/mac_oldworld.c5
-rw-r--r--hw/ppc/ppc440_bamboo.c5
-rw-r--r--hw/ppc/prep.c2
-rw-r--r--hw/ppc/spapr_pci.c41
-rw-r--r--hw/scsi/esp-pci.c36
-rw-r--r--hw/scsi/esp.c42
-rw-r--r--hw/scsi/lsi53c895a.c79
-rw-r--r--hw/scsi/megasas.c71
-rw-r--r--hw/scsi/scsi-bus.c22
-rw-r--r--hw/scsi/spapr_vscsi.c7
-rw-r--r--hw/scsi/virtio-scsi.c7
-rw-r--r--hw/scsi/vmw_pvscsi.c4
-rw-r--r--hw/sh4/sh_pci.c42
-rw-r--r--hw/sparc64/sun4u.c6
-rw-r--r--hw/timer/hpet.c51
-rw-r--r--hw/timer/imx_epit.c2
-rw-r--r--hw/timer/imx_gpt.c2
-rw-r--r--hw/usb/ccid-card-passthru.c2
-rw-r--r--hw/usb/dev-smartcard-reader.c2
-rw-r--r--hw/usb/dev-storage.c4
-rw-r--r--hw/usb/hcd-ohci.c51
-rw-r--r--hw/usb/hcd-xhci.c104
-rw-r--r--hw/virtio/Makefile.objs1
-rw-r--r--hw/virtio/dataplane/vring.c8
-rw-r--r--hw/virtio/virtio-mmio.c421
-rw-r--r--hw/virtio/virtio.c40
-rw-r--r--hw/xen/xen_platform.c35
-rw-r--r--hw/xtensa/xtensa_lx60.c8
-rw-r--r--hw/xtensa/xtensa_sim.c10
-rw-r--r--include/block/aio.h7
-rw-r--r--include/block/block.h2
-rw-r--r--include/exec/cpu-all.h22
-rw-r--r--include/exec/cpu-defs.h3
-rw-r--r--include/exec/gdbstub.h8
-rw-r--r--include/exec/softmmu-semi.h18
-rw-r--r--include/hw/arm/arm.h4
-rw-r--r--include/hw/i386/pc.h4
-rw-r--r--include/hw/isa/isa.h3
-rw-r--r--include/hw/loader.h13
-rw-r--r--include/hw/pci-host/q35.h10
-rw-r--r--include/hw/pci/pci_bridge.h1
-rw-r--r--include/hw/pci/pci_ids.h2
-rw-r--r--include/hw/scsi/scsi.h4
-rw-r--r--include/hw/sysbus.h12
-rw-r--r--include/hw/virtio/dataplane/vring.h2
-rw-r--r--include/hw/virtio/virtio-bus.h6
-rw-r--r--include/hw/virtio/virtio-net.h1
-rw-r--r--include/hw/virtio/virtio.h4
-rw-r--r--include/migration/migration.h10
-rw-r--r--include/monitor/monitor.h1
-rw-r--r--include/net/net.h3
-rw-r--r--include/qemu-common.h1
-rw-r--r--include/qemu/bitops.h50
-rw-r--r--include/qom/cpu.h123
-rw-r--r--include/sysemu/device_tree.h59
-rw-r--r--include/sysemu/kvm.h4
-rw-r--r--ioport.c1
-rw-r--r--kvm-all.c12
-rw-r--r--kvm-stub.c4
-rw-r--r--ldscripts/alpha.ld127
-rw-r--r--ldscripts/arm.ld153
-rw-r--r--ldscripts/hppa.ld211
-rw-r--r--ldscripts/i386.ld153
-rw-r--r--ldscripts/ia64.ld209
-rw-r--r--ldscripts/m68k.ld175
-rw-r--r--ldscripts/mips.ld222
-rw-r--r--ldscripts/ppc.ld237
-rw-r--r--ldscripts/ppc64.ld230
-rw-r--r--ldscripts/s390.ld201
-rw-r--r--ldscripts/sparc.ld150
-rw-r--r--ldscripts/sparc64.ld138
-rw-r--r--ldscripts/x86_64.ld180
-rw-r--r--linux-user/arm/syscall.h2
-rw-r--r--linux-user/cpu-uname.c10
-rw-r--r--linux-user/cris/syscall.h2
-rw-r--r--linux-user/i386/syscall.h2
-rw-r--r--linux-user/i386/target_cpu.h19
-rw-r--r--linux-user/m68k/target_cpu.h6
-rw-r--r--linux-user/main.c126
-rw-r--r--linux-user/microblaze/syscall.h2
-rw-r--r--linux-user/mips/syscall.h2
-rw-r--r--linux-user/mips64/syscall.h2
-rw-r--r--linux-user/mmap.c11
-rw-r--r--linux-user/openrisc/target_cpu.h9
-rw-r--r--linux-user/ppc/syscall.h2
-rw-r--r--linux-user/qemu.h20
-rw-r--r--linux-user/s390x/syscall.h2
-rw-r--r--linux-user/signal.c3
-rw-r--r--linux-user/sparc/syscall.h7
-rw-r--r--linux-user/sparc/target_cpu.h16
-rw-r--r--linux-user/sparc64/syscall.h7
-rw-r--r--linux-user/syscall.c88
-rw-r--r--linux-user/syscall_defs.h54
-rw-r--r--memory.c112
-rw-r--r--migration-rdma.c3249
-rw-r--r--migration.c68
-rw-r--r--monitor.c14
-rw-r--r--net/net.c48
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/acpi-dsdt.amlbin4521 -> 4407 bytes
-rw-r--r--pc-bios/bios.binbin131072 -> 131072 bytes
-rwxr-xr-xpc-bios/palcode-clipperbin185703 -> 133550 bytes
-rw-r--r--pc-bios/q35-acpi-dsdt.amlbin7458 -> 7344 bytes
-rw-r--r--po/Makefile33
-rw-r--r--qapi-schema.json96
-rw-r--r--qemu-char.c41
-rw-r--r--qemu-options.hx4
-rw-r--r--qemu.sasl2
-rw-r--r--qga/service-win32.c105
-rw-r--r--qmp-commands.hx70
-rw-r--r--qtest.c7
m---------roms/qemu-palcode0
m---------roms/seabios0
-rw-r--r--savevm.c2
-rwxr-xr-xscripts/cleanup-trace-events.pl51
-rw-r--r--scripts/qapi-commands.py17
-rw-r--r--slirp/mbuf.h51
-rw-r--r--slirp/tcp_subr.c12
-rw-r--r--target-alpha/cpu-qom.h1
-rw-r--r--target-alpha/cpu.c15
-rw-r--r--target-alpha/cpu.h5
-rw-r--r--target-alpha/helper.c5
-rw-r--r--target-alpha/helper.h3
-rw-r--r--target-alpha/sys_helper.c7
-rw-r--r--target-alpha/translate.c33
-rw-r--r--target-arm/arm-semi.c10
-rw-r--r--target-arm/cpu-qom.h2
-rw-r--r--target-arm/cpu.c13
-rw-r--r--target-arm/cpu.h5
-rw-r--r--target-arm/helper.c15
-rw-r--r--target-arm/translate.c7
-rw-r--r--target-cris/cpu-qom.h2
-rw-r--r--target-cris/cpu.c11
-rw-r--r--target-cris/cpu.h4
-rw-r--r--target-cris/helper.c7
-rw-r--r--target-cris/translate.c7
-rw-r--r--target-i386/cpu-qom.h2
-rw-r--r--target-i386/cpu.c19
-rw-r--r--target-i386/cpu.h5
-rw-r--r--target-i386/helper.c12
-rw-r--r--target-i386/kvm.c20
-rw-r--r--target-i386/machine.c36
-rw-r--r--target-i386/translate.c5
-rw-r--r--target-lm32/cpu-qom.h1
-rw-r--r--target-lm32/cpu.c13
-rw-r--r--target-lm32/cpu.h5
-rw-r--r--target-lm32/helper.c6
-rw-r--r--target-lm32/translate.c7
-rw-r--r--target-m68k/cpu-qom.h1
-rw-r--r--target-m68k/cpu.c11
-rw-r--r--target-m68k/cpu.h5
-rw-r--r--target-m68k/helper.c5
-rw-r--r--target-m68k/m68k-semi.c5
-rw-r--r--target-m68k/translate.c7
-rw-r--r--target-microblaze/cpu-qom.h1
-rw-r--r--target-microblaze/cpu.c13
-rw-r--r--target-microblaze/cpu.h5
-rw-r--r--target-microblaze/helper.c4
-rw-r--r--target-microblaze/translate.c8
-rw-r--r--target-mips/cpu-qom.h1
-rw-r--r--target-mips/cpu.c30
-rw-r--r--target-mips/cpu.h7
-rw-r--r--target-mips/helper.c7
-rw-r--r--target-mips/translate.c11
-rw-r--r--target-moxie/cpu.c13
-rw-r--r--target-moxie/cpu.h6
-rw-r--r--target-moxie/helper.c11
-rw-r--r--target-moxie/translate.c5
-rw-r--r--target-openrisc/cpu.c14
-rw-r--r--target-openrisc/cpu.h6
-rw-r--r--target-openrisc/mmu.c5
-rw-r--r--target-openrisc/translate.c7
-rw-r--r--target-ppc/cpu-qom.h1
-rw-r--r--target-ppc/cpu.h5
-rw-r--r--target-ppc/mmu_helper.c4
-rw-r--r--target-ppc/translate.c8
-rw-r--r--target-ppc/translate_init.c26
-rw-r--r--target-s390x/cpu-qom.h1
-rw-r--r--target-s390x/cpu.c11
-rw-r--r--target-s390x/cpu.h5
-rw-r--r--target-s390x/helper.c5
-rw-r--r--target-s390x/translate.c5
-rw-r--r--target-sh4/cpu-qom.h1
-rw-r--r--target-sh4/cpu.c20
-rw-r--r--target-sh4/cpu.h6
-rw-r--r--target-sh4/helper.c5
-rw-r--r--target-sh4/translate.c8
-rw-r--r--target-sparc/cpu-qom.h1
-rw-r--r--target-sparc/cpu.c26
-rw-r--r--target-sparc/cpu.h11
-rw-r--r--target-sparc/mmu_helper.c22
-rw-r--r--target-sparc/translate.c3
-rw-r--r--target-unicore32/cpu-qom.h1
-rw-r--r--target-unicore32/cpu.c11
-rw-r--r--target-unicore32/cpu.h5
-rw-r--r--target-unicore32/softmmu.c7
-rw-r--r--target-unicore32/translate.c7
-rw-r--r--target-xtensa/cpu-qom.h1
-rw-r--r--target-xtensa/cpu.c11
-rw-r--r--target-xtensa/cpu.h5
-rw-r--r--target-xtensa/helper.c7
-rw-r--r--target-xtensa/translate.c7
-rw-r--r--target-xtensa/xtensa-semi.c14
-rw-r--r--tests/Makefile23
-rw-r--r--tests/boot-order-test.c209
-rw-r--r--tests/endianness-test.c316
-rw-r--r--tests/fdc-test.c2
-rw-r--r--tests/fw_cfg-test.c2
-rw-r--r--tests/hd-geo-test.c8
-rw-r--r--tests/ide-test.c2
-rw-r--r--tests/libqos/fw_cfg-pc.c40
-rw-r--r--tests/libqos/fw_cfg-pc.h20
-rw-r--r--tests/libqos/fw_cfg.c55
-rw-r--r--tests/libqos/fw_cfg.h9
-rw-r--r--tests/libqos/malloc-pc.c2
-rw-r--r--tests/libqtest.c4
-rw-r--r--tests/libqtest.h12
-rw-r--r--tests/test-bitops.c75
-rw-r--r--trace-events177
-rw-r--r--translate-all.c10
-rw-r--r--ui/gtk.c39
-rw-r--r--user-exec.c4
305 files changed, 8671 insertions, 4846 deletions
diff --git a/.gitmodules b/.gitmodules
index b426ea605a..d7e3f3c7cd 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -15,7 +15,7 @@
url = git://git.qemu.org/openbios.git
[submodule "roms/qemu-palcode"]
path = roms/qemu-palcode
- url = git://repo.or.cz/qemu-palcode.git
+ url = git://github.com/rth7680/qemu-palcode.git
[submodule "roms/sgabios"]
path = roms/sgabios
url = git://git.qemu.org/sgabios.git
diff --git a/HACKING b/HACKING
index e73ac79fe9..12fbc8afe4 100644
--- a/HACKING
+++ b/HACKING
@@ -40,8 +40,23 @@ speaking, the size of guest memory can always fit into ram_addr_t but
it would not be correct to store an actual guest physical address in a
ram_addr_t.
-Use target_ulong (or abi_ulong) for CPU virtual addresses, however
-devices should not need to use target_ulong.
+For CPU virtual addresses there are several possible types.
+vaddr is the best type to use to hold a CPU virtual address in
+target-independent code. It is guaranteed to be large enough to hold a
+virtual address for any target, and it does not change size from target
+to target. It is always unsigned.
+target_ulong is a type the size of a virtual address on the CPU; this means
+it may be 32 or 64 bits depending on which target is being built. It should
+therefore be used only in target-specific code, and in some
+performance-critical built-per-target core code such as the TLB code.
+There is also a signed version, target_long.
+abi_ulong is for the *-user targets, and represents a type the size of
+'void *' in that target's ABI. (This may not be the same as the size of a
+full CPU virtual address in the case of target ABIs which use 32 bit pointers
+on 64 bit CPUs, like sparc32plus.) Definitions of structures that must match
+the target's ABI must use this type for anything that on the target is defined
+to be an 'unsigned long' or a pointer type.
+There is also a signed version, abi_long.
Of course, take all of the above with a grain of salt. If you're about
to use some system interface that requires a type like size_t, pid_t or
diff --git a/Makefile.objs b/Makefile.objs
index 5b288ba42f..9928542cdf 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -51,6 +51,7 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += migration.o migration-tcp.o
+common-obj-$(CONFIG_RDMA) += migration-rdma.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o
common-obj-y += page_cache.o xbzrle.o
diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index 24e804e948..39b6016460 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -172,6 +172,23 @@ Data:
},
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+NIC_RX_FILTER_CHANGED
+-----------------
+
+The event is emitted once until the query command is executed,
+the first event will always be emitted.
+
+Data:
+
+- "name": net client name (json-string)
+- "path": device path (json-string)
+
+{ "event": "NIC_RX_FILTER_CHANGED",
+ "data": { "name": "vnet0",
+ "path": "/machine/peripheral/vnet0/virtio-backend" },
+ "timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
+}
+
RESET
-----
diff --git a/arch_init.c b/arch_init.c
index 0e553c9285..68a7ab784f 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -104,6 +104,9 @@ int graphic_depth = 32;
#endif
const uint32_t arch_type = QEMU_ARCH;
+static bool mig_throttle_on;
+static int dirty_rate_high_cnt;
+static void check_guest_throttling(void);
/***********************************************************/
/* ram save/restore */
@@ -115,6 +118,7 @@ const uint32_t arch_type = QEMU_ARCH;
#define RAM_SAVE_FLAG_EOS 0x10
#define RAM_SAVE_FLAG_CONTINUE 0x20
#define RAM_SAVE_FLAG_XBZRLE 0x40
+/* 0x80 is reserved in migration.h start with 0x100 next */
static struct defconfig_file {
@@ -378,8 +382,14 @@ static void migration_bitmap_sync(void)
uint64_t num_dirty_pages_init = migration_dirty_pages;
MigrationState *s = migrate_get_current();
static int64_t start_time;
+ static int64_t bytes_xfer_prev;
static int64_t num_dirty_pages_period;
int64_t end_time;
+ int64_t bytes_xfer_now;
+
+ if (!bytes_xfer_prev) {
+ bytes_xfer_prev = ram_bytes_transferred();
+ }
if (!start_time) {
start_time = qemu_get_clock_ms(rt_clock);
@@ -404,6 +414,25 @@ static void migration_bitmap_sync(void)
/* more than 1 second = 1000 millisecons */
if (end_time > start_time + 1000) {
+ if (migrate_auto_converge()) {
+ /* The following detection logic can be refined later. For now:
+ Check to see if the dirtied bytes is 50% more than the approx.
+ amount of bytes that just got transferred since the last time we
+ were in this routine. If that happens >N times (for now N==4)
+ we turn on the throttle down logic */
+ bytes_xfer_now = ram_bytes_transferred();
+ if (s->dirty_pages_rate &&
+ (num_dirty_pages_period * TARGET_PAGE_SIZE >
+ (bytes_xfer_now - bytes_xfer_prev)/2) &&
+ (dirty_rate_high_cnt++ > 4)) {
+ trace_migration_throttle();
+ mig_throttle_on = true;
+ dirty_rate_high_cnt = 0;
+ }
+ bytes_xfer_prev = bytes_xfer_now;
+ } else {
+ mig_throttle_on = false;
+ }
s->dirty_pages_rate = num_dirty_pages_period * 1000
/ (end_time - start_time);
s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
@@ -447,6 +476,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
ram_bulk_stage = false;
}
} else {
+ int ret;
uint8_t *p;
int cont = (block == last_sent_block) ?
RAM_SAVE_FLAG_CONTINUE : 0;
@@ -455,7 +485,18 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
/* In doubt sent page as normal */
bytes_sent = -1;
- if (is_zero_page(p)) {
+ ret = ram_control_save_page(f, block->offset,
+ offset, TARGET_PAGE_SIZE, &bytes_sent);
+
+ if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
+ if (ret != RAM_SAVE_CONTROL_DELAYED) {
+ if (bytes_sent > 0) {
+ acct_info.norm_pages++;
+ } else if (bytes_sent == 0) {
+ acct_info.dup_pages++;
+ }
+ }
+ } else if (is_zero_page(p)) {
acct_info.dup_pages++;
bytes_sent = save_block_hdr(f, block, offset, cont,
RAM_SAVE_FLAG_COMPRESS);
@@ -573,6 +614,8 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
migration_bitmap = bitmap_new(ram_pages);
bitmap_set(migration_bitmap, 0, ram_pages);
migration_dirty_pages = ram_pages;
+ mig_throttle_on = false;
+ dirty_rate_high_cnt = 0;
if (migrate_use_xbzrle()) {
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
@@ -605,6 +648,10 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
}
qemu_mutex_unlock_ramlist();
+
+ ram_control_before_iterate(f, RAM_CONTROL_SETUP);
+ ram_control_after_iterate(f, RAM_CONTROL_SETUP);
+
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
return 0;
@@ -623,6 +670,8 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
reset_ram_globals();
}
+ ram_control_before_iterate(f, RAM_CONTROL_ROUND);
+
t0 = qemu_get_clock_ns(rt_clock);
i = 0;
while ((ret = qemu_file_rate_limit(f)) == 0) {
@@ -635,6 +684,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
}
total_sent += bytes_sent;
acct_info.iterations++;
+ check_guest_throttling();
/* we want to check in the 1st loop, just in case it was the 1st time
and we had to sync the dirty bitmap.
qemu_get_clock_ns() is a bit expensive, so we only check each some
@@ -653,6 +703,12 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
qemu_mutex_unlock_ramlist();
+ /*
+ * Must occur before EOS (or any QEMUFile operation)
+ * because of RDMA protocol.
+ */
+ ram_control_after_iterate(f, RAM_CONTROL_ROUND);
+
if (ret < 0) {
bytes_transferred += total_sent;
return ret;
@@ -670,6 +726,8 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
qemu_mutex_lock_ramlist();
migration_bitmap_sync();
+ ram_control_before_iterate(f, RAM_CONTROL_FINISH);
+
/* try transferring iterative blocks of memory */
/* flush all remaining blocks regardless of rate limiting */
@@ -683,6 +741,8 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
}
bytes_transferred += bytes_sent;
}
+
+ ram_control_after_iterate(f, RAM_CONTROL_FINISH);
migration_end();
qemu_mutex_unlock_ramlist();
@@ -777,6 +837,24 @@ static inline void *host_from_stream_offset(QEMUFile *f,
return NULL;
}
+/*
+ * If a page (or a whole RDMA chunk) has been
+ * determined to be zero, then zap it.
+ */
+void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
+{
+ if (ch != 0 || !is_zero_page(host)) {
+ memset(host, ch, size);
+#ifndef _WIN32
+ if (ch == 0 &&
+ (!kvm_enabled() || kvm_has_sync_mmu()) &&
+ getpagesize() <= TARGET_PAGE_SIZE) {
+ qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
+ }
+#endif
+ }
+}
+
static int ram_load(QEMUFile *f, void *opaque, int version_id)
{
ram_addr_t addr;
@@ -848,16 +926,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
}
ch = qemu_get_byte(f);
- if (ch != 0 || !is_zero_page(host)) {
- memset(host, ch, TARGET_PAGE_SIZE);
-#ifndef _WIN32
- if (ch == 0 &&
- (!kvm_enabled() || kvm_has_sync_mmu()) &&
- getpagesize() <= TARGET_PAGE_SIZE) {
- qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
- }
-#endif
- }
+ ram_handle_compressed(host, ch, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_PAGE) {
void *host;
@@ -877,6 +946,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ret = -EINVAL;
goto done;
}
+ } else if (flags & RAM_SAVE_FLAG_HOOK) {
+ ram_control_load_hook(f, flags);
}
error = qemu_file_get_error(f);
if (error) {
@@ -1110,3 +1181,53 @@ TargetInfo *qmp_query_target(Error **errp)
return info;
}
+
+/* Stub function that's gets run on the vcpu when its brought out of the
+ VM to run inside qemu via async_run_on_cpu()*/
+static void mig_sleep_cpu(void *opq)
+{
+ qemu_mutex_unlock_iothread();
+ g_usleep(30*1000);
+ qemu_mutex_lock_iothread();
+}
+
+/* To reduce the dirty rate explicitly disallow the VCPUs from spending
+ much time in the VM. The migration thread will try to catchup.
+ Workload will experience a performance drop.
+*/
+static void mig_throttle_cpu_down(CPUState *cpu, void *data)
+{
+ async_run_on_cpu(cpu, mig_sleep_cpu, NULL);
+}
+
+static void mig_throttle_guest_down(void)
+{
+ qemu_mutex_lock_iothread();
+ qemu_for_each_cpu(mig_throttle_cpu_down, NULL);
+ qemu_mutex_unlock_iothread();
+}
+
+static void check_guest_throttling(void)
+{
+ static int64_t t0;
+ int64_t t1;
+
+ if (!mig_throttle_on) {
+ return;
+ }
+
+ if (!t0) {
+ t0 = qemu_get_clock_ns(rt_clock);
+ return;
+ }
+
+ t1 = qemu_get_clock_ns(rt_clock);
+
+ /* If it has been more than 40 ms since the last time the guest
+ * was throttled then do it again.
+ */
+ if (40 < (t1-t0)/1000000) {
+ mig_throttle_guest_down();
+ t0 = t1;
+ }
+}
diff --git a/async.c b/async.c
index 90fe906539..5ce3633010 100644
--- a/async.c
+++ b/async.c
@@ -47,11 +47,16 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
bh->ctx = ctx;
bh->cb = cb;
bh->opaque = opaque;
+ qemu_mutex_lock(&ctx->bh_lock);
bh->next = ctx->first_bh;
+ /* Make sure that the members are ready before putting bh into list */
+ smp_wmb();
ctx->first_bh = bh;
+ qemu_mutex_unlock(&ctx->bh_lock);
return bh;
}
+/* Multiple occurrences of aio_bh_poll cannot be called concurrently */
int aio_bh_poll(AioContext *ctx)
{
QEMUBH *bh, **bhp, *next;
@@ -61,9 +66,15 @@ int aio_bh_poll(AioContext *ctx)
ret = 0;
for (bh = ctx->first_bh; bh; bh = next) {
+ /* Make sure that fetching bh happens before accessing its members */
+ smp_read_barrier_depends();
next = bh->next;
if (!bh->deleted && bh->scheduled) {
bh->scheduled = 0;
+ /* Paired with write barrier in bh schedule to ensure reading for
+ * idle & callbacks coming after bh's scheduling.
+ */
+ smp_rmb();
if (!bh->idle)
ret = 1;
bh->idle = 0;
@@ -75,6 +86,7 @@ int aio_bh_poll(AioContext *ctx)
/* remove deleted bhs */
if (!ctx->walking_bh) {
+ qemu_mutex_lock(&ctx->bh_lock);
bhp = &ctx->first_bh;
while (*bhp) {
bh = *bhp;
@@ -85,6 +97,7 @@ int aio_bh_poll(AioContext *ctx)
bhp = &bh->next;
}
}
+ qemu_mutex_unlock(&ctx->bh_lock);
}
return ret;
@@ -94,24 +107,38 @@ void qemu_bh_schedule_idle(QEMUBH *bh)
{
if (bh->scheduled)
return;
- bh->scheduled = 1;
bh->idle = 1;
+ /* Make sure that idle & any writes needed by the callback are done
+ * before the locations are read in the aio_bh_poll.
+ */
+ smp_wmb();
+ bh->scheduled = 1;
}
void qemu_bh_schedule(QEMUBH *bh)
{
if (bh->scheduled)
return;
- bh->scheduled = 1;
bh->idle = 0;
+ /* Make sure that idle & any writes needed by the callback are done
+ * before the locations are read in the aio_bh_poll.
+ */
+ smp_wmb();
+ bh->scheduled = 1;
aio_notify(bh->ctx);
}
+
+/* This func is async.
+ */
void qemu_bh_cancel(QEMUBH *bh)
{
bh->scheduled = 0;
}
+/* This func is async.The bottom half will do the delete action at the finial
+ * end.
+ */
void qemu_bh_delete(QEMUBH *bh)
{
bh->scheduled = 0;
@@ -176,6 +203,7 @@ aio_ctx_finalize(GSource *source)
thread_pool_free(ctx->thread_pool);
aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
event_notifier_cleanup(&ctx->notifier);
+ qemu_mutex_destroy(&ctx->bh_lock);
g_array_free(ctx->pollfds, TRUE);
}
@@ -211,6 +239,7 @@ AioContext *aio_context_new(void)
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
ctx->thread_pool = NULL;
+ qemu_mutex_init(&ctx->bh_lock);
event_notifier_init(&ctx->notifier, false);
aio_set_event_notifier(ctx, &ctx->notifier,
(EventNotifierHandler *)
diff --git a/block-migration.c b/block-migration.c
index 2fd7699794..f803f2006f 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -29,6 +29,7 @@
#define BLK_MIG_FLAG_DEVICE_BLOCK 0x01
#define BLK_MIG_FLAG_EOS 0x02
#define BLK_MIG_FLAG_PROGRESS 0x04
+#define BLK_MIG_FLAG_ZERO_BLOCK 0x08
#define MAX_IS_ALLOCATED_SEARCH 65536
@@ -80,6 +81,7 @@ typedef struct BlkMigState {
int shared_base;
QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list;
int64_t total_sector_sum;
+ bool zero_blocks;
/* Protected by lock. */
QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list;
@@ -114,16 +116,30 @@ static void blk_mig_unlock(void)
static void blk_send(QEMUFile *f, BlkMigBlock * blk)
{
int len;
+ uint64_t flags = BLK_MIG_FLAG_DEVICE_BLOCK;
+
+ if (block_mig_state.zero_blocks &&
+ buffer_is_zero(blk->buf, BLOCK_SIZE)) {
+ flags |= BLK_MIG_FLAG_ZERO_BLOCK;
+ }
/* sector number and flags */
qemu_put_be64(f, (blk->sector << BDRV_SECTOR_BITS)
- | BLK_MIG_FLAG_DEVICE_BLOCK);
+ | flags);
/* device name */
len = strlen(blk->bmds->bs->device_name);
qemu_put_byte(f, len);
qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len);
+ /* if a block is zero we need to flush here since the network
+ * bandwidth is now a lot higher than the storage device bandwidth.
+ * thus if we queue zero blocks we slow down the migration */
+ if (flags & BLK_MIG_FLAG_ZERO_BLOCK) {
+ qemu_fflush(f);
+ return;
+ }
+
qemu_put_buffer(f, blk->buf, BLOCK_SIZE);
}
@@ -344,6 +360,7 @@ static void init_blk_migration(QEMUFile *f)
block_mig_state.total_sector_sum = 0;
block_mig_state.prev_progress = -1;
block_mig_state.bulk_completed = 0;
+ block_mig_state.zero_blocks = migrate_zero_blocks();
bdrv_iterate(init_blk_migration_it, NULL);
}
@@ -762,12 +779,15 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
}
- buf = g_malloc(BLOCK_SIZE);
-
- qemu_get_buffer(f, buf, BLOCK_SIZE);
- ret = bdrv_write(bs, addr, buf, nr_sectors);
+ if (flags & BLK_MIG_FLAG_ZERO_BLOCK) {
+ ret = bdrv_write_zeroes(bs, addr, nr_sectors);
+ } else {
+ buf = g_malloc(BLOCK_SIZE);
+ qemu_get_buffer(f, buf, BLOCK_SIZE);
+ ret = bdrv_write(bs, addr, buf, nr_sectors);
+ g_free(buf);
+ }
- g_free(buf);
if (ret < 0) {
return ret;
}
diff --git a/block.c b/block.c
index b56024113b..6cd39fa146 100644
--- a/block.c
+++ b/block.c
@@ -2162,6 +2162,7 @@ typedef struct RwCo {
QEMUIOVector *qiov;
bool is_write;
int ret;
+ BdrvRequestFlags flags;
} RwCo;
static void coroutine_fn bdrv_rw_co_entry(void *opaque)
@@ -2170,10 +2171,12 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
if (!rwco->is_write) {
rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num,
- rwco->nb_sectors, rwco->qiov, 0);
+ rwco->nb_sectors, rwco->qiov,
+ rwco->flags);
} else {
rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
- rwco->nb_sectors, rwco->qiov, 0);
+ rwco->nb_sectors, rwco->qiov,
+ rwco->flags);
}
}
@@ -2181,7 +2184,8 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
* Process a vectored synchronous request using coroutines
*/
static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, bool is_write)
+ QEMUIOVector *qiov, bool is_write,
+ BdrvRequestFlags flags)
{
Coroutine *co;
RwCo rwco = {
@@ -2191,6 +2195,7 @@ static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num,
.qiov = qiov,
.is_write = is_write,
.ret = NOT_DONE,
+ .flags = flags,
};
assert((qiov->size & (BDRV_SECTOR_SIZE - 1)) == 0);
@@ -2222,7 +2227,7 @@ static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num,
* Process a synchronous request using coroutines
*/
static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
- int nb_sectors, bool is_write)
+ int nb_sectors, bool is_write, BdrvRequestFlags flags)
{
QEMUIOVector qiov;
struct iovec iov = {
@@ -2231,14 +2236,14 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
};
qemu_iovec_init_external(&qiov, &iov, 1);
- return bdrv_rwv_co(bs, sector_num, &qiov, is_write);
+ return bdrv_rwv_co(bs, sector_num, &qiov, is_write, flags);
}
/* return < 0 if error. See bdrv_write() for the return codes */
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
- return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false);
+ return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false, 0);
}
/* Just like bdrv_read(), but with I/O throttling temporarily disabled */
@@ -2250,7 +2255,7 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
enabled = bs->io_limits_enabled;
bs->io_limits_enabled = false;
- ret = bdrv_read(bs, 0, buf, 1);
+ ret = bdrv_read(bs, sector_num, buf, nb_sectors);
bs->io_limits_enabled = enabled;
return ret;
}
@@ -2264,12 +2269,18 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
- return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true);
+ return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true, 0);
}
int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov)
{
- return bdrv_rwv_co(bs, sector_num, qiov, true);
+ return bdrv_rwv_co(bs, sector_num, qiov, true, 0);
+}
+
+int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+ return bdrv_rw_co(bs, sector_num, NULL, nb_sectors, true,
+ BDRV_REQ_ZERO_WRITE);
}
int bdrv_pread(BlockDriverState *bs, int64_t offset,
diff --git a/block/gluster.c b/block/gluster.c
index 61424bcb01..6de418c0bd 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -532,6 +532,39 @@ out:
return NULL;
}
+#ifdef CONFIG_GLUSTERFS_DISCARD
+static BlockDriverAIOCB *qemu_gluster_aio_discard(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ int ret;
+ GlusterAIOCB *acb;
+ BDRVGlusterState *s = bs->opaque;
+ size_t size;
+ off_t offset;
+
+ offset = sector_num * BDRV_SECTOR_SIZE;
+ size = nb_sectors * BDRV_SECTOR_SIZE;
+
+ acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
+ acb->size = 0;
+ acb->ret = 0;
+ acb->finished = NULL;
+ s->qemu_aio_count++;
+
+ ret = glfs_discard_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
+ if (ret < 0) {
+ goto out;
+ }
+ return &acb->common;
+
+out:
+ s->qemu_aio_count--;
+ qemu_aio_release(acb);
+ return NULL;
+}
+#endif
+
static int64_t qemu_gluster_getlength(BlockDriverState *bs)
{
BDRVGlusterState *s = bs->opaque;
@@ -602,6 +635,9 @@ static BlockDriver bdrv_gluster = {
.bdrv_aio_writev = qemu_gluster_aio_writev,
.bdrv_aio_flush = qemu_gluster_aio_flush,
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
+#ifdef CONFIG_GLUSTERFS_DISCARD
+ .bdrv_aio_discard = qemu_gluster_aio_discard,
+#endif
.create_options = qemu_gluster_create_options,
};
@@ -618,6 +654,9 @@ static BlockDriver bdrv_gluster_tcp = {
.bdrv_aio_writev = qemu_gluster_aio_writev,
.bdrv_aio_flush = qemu_gluster_aio_flush,
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
+#ifdef CONFIG_GLUSTERFS_DISCARD
+ .bdrv_aio_discard = qemu_gluster_aio_discard,
+#endif
.create_options = qemu_gluster_create_options,
};
@@ -634,6 +673,9 @@ static BlockDriver bdrv_gluster_unix = {
.bdrv_aio_writev = qemu_gluster_aio_writev,
.bdrv_aio_flush = qemu_gluster_aio_flush,
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
+#ifdef CONFIG_GLUSTERFS_DISCARD
+ .bdrv_aio_discard = qemu_gluster_aio_discard,
+#endif
.create_options = qemu_gluster_create_options,
};
@@ -650,6 +692,9 @@ static BlockDriver bdrv_gluster_rdma = {
.bdrv_aio_writev = qemu_gluster_aio_writev,
.bdrv_aio_flush = qemu_gluster_aio_flush,
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
+#ifdef CONFIG_GLUSTERFS_DISCARD
+ .bdrv_aio_discard = qemu_gluster_aio_discard,
+#endif
.create_options = qemu_gluster_create_options,
};
diff --git a/block/iscsi.c b/block/iscsi.c
index 0bbf0b18b4..5f28c6a2ea 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -32,6 +32,7 @@
#include "block/block_int.h"
#include "trace.h"
#include "block/scsi.h"
+#include "qemu/iov.h"
#include <iscsi/iscsi.h>
#include <iscsi/scsi-lowlevel.h>
@@ -61,8 +62,6 @@ typedef struct IscsiAIOCB {
int status;
int canceled;
int retries;
- size_t read_size;
- size_t read_offset;
int64_t sector_num;
int nb_sectors;
#ifdef __linux__
@@ -233,11 +232,28 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
iscsi_schedule_bh(acb);
}
+static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun)
+{
+ return sector * iscsilun->block_size / BDRV_SECTOR_SIZE;
+}
+
static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
{
return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
}
+static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
+ IscsiLun *iscsilun)
+{
+ if ((sector_num * BDRV_SECTOR_SIZE) % iscsilun->block_size ||
+ (nb_sectors * BDRV_SECTOR_SIZE) % iscsilun->block_size) {
+ error_report("iSCSI misaligned request: iscsilun->block_size %u, sector_num %ld, nb_sectors %d",
+ iscsilun->block_size, sector_num, nb_sectors);
+ return 0;
+ }
+ return 1;
+}
+
static int
iscsi_aio_writev_acb(IscsiAIOCB *acb)
{
@@ -285,7 +301,7 @@ iscsi_aio_writev_acb(IscsiAIOCB *acb)
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
- num_sectors = size / acb->iscsilun->block_size;
+ num_sectors = sector_qemu2lun(acb->nb_sectors, acb->iscsilun);
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
acb->task->expxferlen = size;
@@ -322,6 +338,10 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
IscsiLun *iscsilun = bs->opaque;
IscsiAIOCB *acb;
+ if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
+ return NULL;
+ }
+
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
@@ -379,6 +399,7 @@ static int
iscsi_aio_readv_acb(IscsiAIOCB *acb)
{
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
+ size_t size;
uint64_t lba;
uint32_t num_sectors;
int ret;
@@ -391,20 +412,7 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb)
acb->status = -EINPROGRESS;
acb->buf = NULL;
- /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
- * may be misaligned to the LUN, so we may need to read some extra
- * data.
- */
- acb->read_offset = 0;
- if (acb->iscsilun->block_size > BDRV_SECTOR_SIZE) {
- uint64_t bdrv_offset = BDRV_SECTOR_SIZE * acb->sector_num;
-
- acb->read_offset = bdrv_offset % acb->iscsilun->block_size;
- }
-
- num_sectors = (acb->read_size + acb->iscsilun->block_size
- + acb->read_offset - 1)
- / acb->iscsilun->block_size;
+ size = acb->nb_sectors * BDRV_SECTOR_SIZE;
acb->task = malloc(sizeof(struct scsi_task));
if (acb->task == NULL) {
@@ -415,8 +423,9 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb)
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_READ;
+ acb->task->expxferlen = size;
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
- acb->task->expxferlen = acb->read_size;
+ num_sectors = sector_qemu2lun(acb->nb_sectors, acb->iscsilun);
switch (acb->iscsilun->type) {
case TYPE_DISK:
@@ -464,6 +473,10 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
IscsiLun *iscsilun = bs->opaque;
IscsiAIOCB *acb;
+ if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
+ return NULL;
+ }
+
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
@@ -471,7 +484,6 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
acb->sector_num = sector_num;
acb->iscsilun = iscsilun;
acb->qiov = qiov;
- acb->read_size = BDRV_SECTOR_SIZE * (size_t)acb->nb_sectors;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_readv_acb(acb) != 0) {
@@ -651,6 +663,9 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
{
IscsiAIOCB *acb = opaque;
+ g_free(acb->buf);
+ acb->buf = NULL;
+
if (acb->canceled != 0) {
return;
}
@@ -727,14 +742,30 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
memcpy(&acb->task->cdb[0], acb->ioh->cmdp, acb->ioh->cmd_len);
acb->task->expxferlen = acb->ioh->dxfer_len;
+ data.size = 0;
if (acb->task->xfer_dir == SCSI_XFER_WRITE) {
- data.data = acb->ioh->dxferp;
- data.size = acb->ioh->dxfer_len;
+ if (acb->ioh->iovec_count == 0) {
+ data.data = acb->ioh->dxferp;
+ data.size = acb->ioh->dxfer_len;
+ } else {
+#if defined(LIBISCSI_FEATURE_IOVECTOR)
+ scsi_task_set_iov_out(acb->task,
+ (struct scsi_iovec *) acb->ioh->dxferp,
+ acb->ioh->iovec_count);
+#else
+ struct iovec *iov = (struct iovec *)acb->ioh->dxferp;
+
+ acb->buf = g_malloc(acb->ioh->dxfer_len);
+ data.data = acb->buf;
+ data.size = iov_to_buf(iov, acb->ioh->iovec_count, 0,
+ acb->buf, acb->ioh->dxfer_len);
+#endif
+ }
}
+
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
iscsi_aio_ioctl_cb,
- (acb->task->xfer_dir == SCSI_XFER_WRITE) ?
- &data : NULL,
+ (data.size > 0) ? &data : NULL,
acb) != 0) {
scsi_free_scsi_task(acb->task);
qemu_aio_release(acb);
@@ -743,9 +774,26 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
/* tell libiscsi to read straight into the buffer we got from ioctl */
if (acb->task->xfer_dir == SCSI_XFER_READ) {
- scsi_task_add_data_in_buffer(acb->task,
- acb->ioh->dxfer_len,
- acb->ioh->dxferp);
+ if (acb->ioh->iovec_count == 0) {
+ scsi_task_add_data_in_buffer(acb->task,
+ acb->ioh->dxfer_len,
+ acb->ioh->dxferp);
+ } else {
+#if defined(LIBISCSI_FEATURE_IOVECTOR)
+ scsi_task_set_iov_in(acb->task,
+ (struct scsi_iovec *) acb->ioh->dxferp,
+ acb->ioh->iovec_count);
+#else
+ int i;
+ for (i = 0; i < acb->ioh->iovec_count; i++) {
+ struct iovec *iov = (struct iovec *)acb->ioh->dxferp;
+
+ scsi_task_add_data_in_buffer(acb->task,
+ iov[i].iov_len,
+ iov[i].iov_base);
+ }
+#endif
+ }
}
iscsi_set_events(iscsilun);
@@ -1118,8 +1166,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
goto out;
}
- bs->total_sectors = iscsilun->num_blocks *
- iscsilun->block_size / BDRV_SECTOR_SIZE ;
+ bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
/* Medium changer or tape. We dont have any emulation for this so this must
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
@@ -1235,6 +1282,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options)
}
if (bs.total_sectors < total_size) {
ret = -ENOSPC;
+ goto out;
}
ret = 0;
diff --git a/block/raw.c b/block/raw.c
index ce10422006..f1682d4f32 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -42,6 +42,13 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
return bdrv_co_is_allocated(bs->file, sector_num, nb_sectors, pnum);
}
+static int coroutine_fn raw_co_write_zeroes(BlockDriverState *bs,
+ int64_t sector_num,
+ int nb_sectors)
+{
+ return bdrv_co_write_zeroes(bs->file, sector_num, nb_sectors);
+}
+
static int64_t raw_getlength(BlockDriverState *bs)
{
return bdrv_getlength(bs->file);
@@ -114,6 +121,11 @@ static int raw_has_zero_init(BlockDriverState *bs)
return bdrv_has_zero_init(bs->file);
}
+static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+ return bdrv_get_info(bs->file, bdi);
+}
+
static BlockDriver bdrv_raw = {
.format_name = "raw",
@@ -128,10 +140,12 @@ static BlockDriver bdrv_raw = {
.bdrv_co_readv = raw_co_readv,
.bdrv_co_writev = raw_co_writev,
.bdrv_co_is_allocated = raw_co_is_allocated,
+ .bdrv_co_write_zeroes = raw_co_write_zeroes,
.bdrv_co_discard = raw_co_discard,
.bdrv_probe = raw_probe,
.bdrv_getlength = raw_getlength,
+ .bdrv_get_info = raw_get_info,
.bdrv_truncate = raw_truncate,
.bdrv_is_inserted = raw_is_inserted,
diff --git a/block/vvfat.c b/block/vvfat.c
index 87b02799d0..cd3b8edd9f 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1164,8 +1164,8 @@ DLOG(if (stderr == NULL) {
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
if (qemu_opt_get_bool(opts, "rw", false)) {
- if (enable_write_target(s)) {
- ret = -EIO;
+ ret = enable_write_target(s);
+ if (ret < 0) {
goto fail;
}
bs->read_only = 0;
@@ -2917,9 +2917,7 @@ static int enable_write_target(BDRVVVFATState *s)
s->qcow_filename = g_malloc(1024);
ret = get_tmp_filename(s->qcow_filename, 1024);
if (ret < 0) {
- g_free(s->qcow_filename);
- s->qcow_filename = NULL;
- return ret;
+ goto err;
}
bdrv_qcow = bdrv_find_format("qcow");
@@ -2927,18 +2925,18 @@ static int enable_write_target(BDRVVVFATState *s)
set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
- if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
- return -1;
+ ret = bdrv_create(bdrv_qcow, s->qcow_filename, options);
+ if (ret < 0) {
+ goto err;
+ }
s->qcow = bdrv_new("");
- if (s->qcow == NULL) {
- return -1;
- }
ret = bdrv_open(s->qcow, s->qcow_filename, NULL,
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
if (ret < 0) {
- return ret;
+ bdrv_delete(s->qcow);
+ goto err;
}
#ifndef _WIN32
@@ -2951,6 +2949,11 @@ static int enable_write_target(BDRVVVFATState *s)
*(void**)s->bs->backing_hd->opaque = s;
return 0;
+
+err:
+ g_free(s->qcow_filename);
+ s->qcow_filename = NULL;
+ return ret;
}
static void vvfat_close(BlockDriverState *bs)
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 1e9255242c..f9246aa102 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -643,7 +643,7 @@ void cpu_loop(CPUSPARCState *env)
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
#if 0
if (sig)
{
@@ -738,6 +738,7 @@ int main(int argc, char **argv)
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
CPUArchState *env;
+ CPUState *cpu;
int optind;
const char *r;
int gdbstub_port = 0;
@@ -912,10 +913,11 @@ int main(int argc, char **argv)
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+ cpu = ENV_GET_CPU(env);
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
- cpu_reset(ENV_GET_CPU(env));
+ cpu_reset(cpu);
#endif
- thread_cpu = ENV_GET_CPU(env);
+ thread_cpu = cpu;
if (getenv("QEMU_STRACE")) {
do_strace = 1;
@@ -1134,7 +1136,7 @@ int main(int argc, char **argv)
if (gdbstub_port) {
gdbserver_start (gdbstub_port);
- gdb_handlesig(env, 0);
+ gdb_handlesig(cpu, 0);
}
cpu_loop(env);
/* never exits */
diff --git a/configure b/configure
index 0214bbc546..f5e299adcf 100755
--- a/configure
+++ b/configure
@@ -155,7 +155,6 @@ curl=""
curses=""
docs=""
fdt=""
-nptl=""
pixman=""
sdl=""
virtfs=""
@@ -180,6 +179,7 @@ xfs=""
vhost_net="no"
vhost_scsi="no"
kvm="no"
+rdma=""
gprof="no"
debug_tcg="no"
debug="no"
@@ -237,6 +237,7 @@ libiscsi=""
coroutine=""
seccomp=""
glusterfs=""
+glusterfs_discard="no"
virtio_blk_data_plane=""
gtk=""
gtkabi="2.0"
@@ -854,10 +855,6 @@ for opt do
;;
--enable-fdt) fdt="yes"
;;
- --disable-nptl) nptl="no"
- ;;
- --enable-nptl) nptl="yes"
- ;;
--enable-mixemu) mixemu="yes"
;;
--disable-linux-aio) linux_aio="no"
@@ -936,6 +933,10 @@ for opt do
;;
--enable-gtk) gtk="yes"
;;
+ --enable-rdma) rdma="yes"
+ ;;
+ --disable-rdma) rdma="no"
+ ;;
--with-gtkabi=*) gtkabi="$optarg"
;;
--enable-tpm) tpm="yes"
@@ -1094,9 +1095,9 @@ echo " --enable-bluez enable bluez stack connectivity"
echo " --disable-slirp disable SLIRP userspace network connectivity"
echo " --disable-kvm disable KVM acceleration support"
echo " --enable-kvm enable KVM acceleration support"
+echo " --disable-rdma disable RDMA-based migration support"
+echo " --enable-rdma enable RDMA-based migration support"
echo " --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)"
-echo " --disable-nptl disable usermode NPTL support"
-echo " --enable-nptl enable usermode NPTL support"
echo " --enable-system enable all system emulation targets"
echo " --disable-system disable all system emulation targets"
echo " --enable-user enable supported user emulation targets"
@@ -1431,7 +1432,7 @@ fi
##########################################
# NPTL probe
-if test "$nptl" != "no" ; then
+if test "$linux_user" = "yes"; then
cat > $TMPC <<EOF
#include <sched.h>
#include <linux/futex.h>
@@ -1442,14 +1443,8 @@ int main(void) {
return 0;
}
EOF
-
- if compile_object ; then
- nptl=yes
- else
- if test "$nptl" = "yes" ; then
- feature_not_found "nptl"
- fi
- nptl=no
+ if ! compile_object ; then
+ feature_not_found "nptl"
fi
fi
@@ -1697,19 +1692,23 @@ if test "$gtk" != "no"; then
vtepackage="vte"
vteversion="0.24.0"
fi
- if $pkg_config --exists "$gtkpackage >= $gtkversion" && \
- $pkg_config --exists "$vtepackage >= $vteversion"; then
+ if ! $pkg_config --exists "$gtkpackage >= $gtkversion"; then
+ if test "$gtk" = "yes" ; then
+ feature_not_found "gtk"
+ fi
+ gtk="no"
+ elif ! $pkg_config --exists "$vtepackage >= $vteversion"; then
+ if test "$gtk" = "yes" ; then
+ error_exit "libvte not found (required for gtk support)"
+ fi
+ gtk="no"
+ else
gtk_cflags=`$pkg_config --cflags $gtkpackage 2>/dev/null`
gtk_libs=`$pkg_config --libs $gtkpackage 2>/dev/null`
vte_cflags=`$pkg_config --cflags $vtepackage 2>/dev/null`
vte_libs=`$pkg_config --libs $vtepackage 2>/dev/null`
libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
gtk="yes"
- else
- if test "$gtk" = "yes" ; then
- feature_not_found "gtk"
- fi
- gtk="no"
fi
fi
@@ -1797,6 +1796,30 @@ EOF
fi
##########################################
+# RDMA needs OpenFabrics libraries
+if test "$rdma" != "no" ; then
+ cat > $TMPC <<EOF
+#include <rdma/rdma_cma.h>
+int main(void) { return 0; }
+EOF
+ rdma_libs="-lrdmacm -libverbs"
+ if compile_prog "" "$rdma_libs" ; then
+ rdma="yes"
+ libs_softmmu="$libs_softmmu $rdma_libs"
+ else
+ if test "$rdma" = "yes" ; then
+ error_exit \
+ " OpenFabrics librdmacm/libibverbs not present." \
+ " Your options:" \
+ " (1) Fast: Install infiniband packages from your distro." \
+ " (2) Cleanest: Install libraries from www.openfabrics.org" \
+ " (3) Also: Install softiwarp if you don't have RDMA hardware"
+ fi
+ rdma="no"
+ fi
+fi
+
+##########################################
# VNC TLS/WS detection
if test "$vnc" = "yes" -a \( "$vnc_tls" != "no" -o "$vnc_ws" != "no" \) ; then
cat > $TMPC <<EOF
@@ -2566,23 +2589,21 @@ fi
##########################################
# glusterfs probe
if test "$glusterfs" != "no" ; then
- cat > $TMPC <<EOF
-#include <glusterfs/api/glfs.h>
-int main(void) {
- (void) glfs_new("volume");
- return 0;
-}
-EOF
- glusterfs_libs="-lgfapi -lgfrpc -lgfxdr"
- if compile_prog "" "$glusterfs_libs" ; then
- glusterfs=yes
+ if $pkg_config --atleast-version=3 glusterfs-api >/dev/null 2>&1; then
+ glusterfs="yes"
+ glusterfs_cflags=`$pkg_config --cflags glusterfs-api 2>/dev/null`
+ glusterfs_libs=`$pkg_config --libs glusterfs-api 2>/dev/null`
+ CFLAGS="$CFLAGS $glusterfs_cflags"
libs_tools="$glusterfs_libs $libs_tools"
libs_softmmu="$glusterfs_libs $libs_softmmu"
+ if $pkg_config --atleast-version=5 glusterfs-api >/dev/null 2>&1; then
+ glusterfs_discard="yes"
+ fi
else
if test "$glusterfs" = "yes" ; then
feature_not_found "GlusterFS backend support"
fi
- glusterfs=no
+ glusterfs="no"
fi
fi
@@ -3547,7 +3568,6 @@ echo "bluez support $bluez"
echo "Documentation $docs"
[ ! -z "$uname_release" ] && \
echo "uname -r $uname_release"
-echo "NPTL support $nptl"
echo "GUEST_BASE $guest_base"
echo "PIE $pie"
echo "vde support $vde"
@@ -3555,6 +3575,7 @@ echo "Linux AIO support $linux_aio"
echo "ATTR/XATTR support $attr"
echo "Install blobs $blobs"
echo "KVM support $kvm"
+echo "RDMA support $rdma"
echo "TCG interpreter $tcg_interpreter"
echo "fdt support $fdt"
echo "preadv support $preadv"
@@ -3965,6 +3986,10 @@ if test "$glusterfs" = "yes" ; then
echo "CONFIG_GLUSTERFS=y" >> $config_host_mak
fi
+if test "$glusterfs_discard" = "yes" ; then
+ echo "CONFIG_GLUSTERFS_DISCARD=y" >> $config_host_mak
+fi
+
if test "$libssh2" = "yes" ; then
echo "CONFIG_LIBSSH2=y" >> $config_host_mak
fi
@@ -4039,6 +4064,10 @@ if test "$trace_default" = "yes"; then
echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak
fi
+if test "$rdma" = "yes" ; then
+ echo "CONFIG_RDMA=y" >> $config_host_mak
+fi
+
if test "$tcg_interpreter" = "yes"; then
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
elif test "$ARCH" = "sparc64" ; then
@@ -4173,7 +4202,6 @@ mkdir -p $target_dir
echo "# Automatically generated by configure - do not modify" > $config_target_mak
bflt="no"
-target_nptl="no"
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_name/g"`
gdb_xml_files=""
@@ -4188,16 +4216,13 @@ case "$target_name" in
TARGET_BASE_ARCH=i386
;;
alpha)
- target_nptl="yes"
;;
arm|armeb)
TARGET_ARCH=arm
bflt="yes"
- target_nptl="yes"
gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
;;
cris)
- target_nptl="yes"
;;
lm32)
;;
@@ -4208,12 +4233,10 @@ case "$target_name" in
microblaze|microblazeel)
TARGET_ARCH=microblaze
bflt="yes"
- target_nptl="yes"
;;
mips|mipsel)
TARGET_ARCH=mips
echo "TARGET_ABI_MIPSO32=y" >> $config_target_mak
- target_nptl="yes"
;;
mipsn32|mipsn32el)
TARGET_ARCH=mips64
@@ -4234,13 +4257,11 @@ case "$target_name" in
;;
ppc)
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
- target_nptl="yes"
;;
ppcemb)
TARGET_BASE_ARCH=ppc
TARGET_ABI_DIR=ppc
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
- target_nptl="yes"
;;
ppc64)
TARGET_BASE_ARCH=ppc
@@ -4257,7 +4278,6 @@ case "$target_name" in
sh4|sh4eb)
TARGET_ARCH=sh4
bflt="yes"
- target_nptl="yes"
;;
sparc)
;;
@@ -4271,7 +4291,6 @@ case "$target_name" in
echo "TARGET_ABI32=y" >> $config_target_mak
;;
s390x)
- target_nptl="yes"
;;
unicore32)
;;
@@ -4353,10 +4372,6 @@ fi
if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
echo "TARGET_HAS_BFLT=y" >> $config_target_mak
fi
-if test "$target_user_only" = "yes" \
- -a "$nptl" = "yes" -a "$target_nptl" = "yes"; then
- echo "CONFIG_USE_NPTL=y" >> $config_target_mak
-fi
if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then
echo "CONFIG_USE_GUEST_BASE=y" >> $config_target_mak
fi
@@ -4478,6 +4493,10 @@ if [ "$pixman" = "internal" ]; then
echo "config-host.h: subdir-pixman" >> $config_host_mak
fi
+if test "$rdma" = "yes" ; then
+echo "CONFIG_RDMA=y" >> $config_host_mak
+fi
+
if [ "$dtc_internal" = "yes" ]; then
echo "config-host.h: subdir-dtc" >> $config_host_mak
fi
diff --git a/cpu-exec.c b/cpu-exec.c
index 6c784a7e09..301be28bf7 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -59,8 +59,14 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
* counter hit zero); we must restore the guest PC to the address
* of the start of the TB.
*/
+ CPUClass *cc = CPU_GET_CLASS(cpu);
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
- cpu_pc_from_tb(env, tb);
+ if (cc->synchronize_from_tb) {
+ cc->synchronize_from_tb(cpu, tb);
+ } else {
+ assert(cc->set_pc);
+ cc->set_pc(cpu, tb->pc);
+ }
}
if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) {
/* We were asked to stop executing TBs (probably a pending
@@ -291,7 +297,7 @@ int cpu_exec(CPUArchState *env)
for(;;) {
interrupt_request = cpu->interrupt_request;
if (unlikely(interrupt_request)) {
- if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
+ if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) {
/* Mask out external interrupts for this step. */
interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
}
diff --git a/cpus.c b/cpus.c
index 29277e109f..ca6b886592 100644
--- a/cpus.c
+++ b/cpus.c
@@ -443,11 +443,12 @@ static int do_vm_stop(RunState state)
pause_all_vcpus();
runstate_set(state);
vm_state_notify(0, state);
- bdrv_drain_all();
- ret = bdrv_flush_all();
monitor_protocol_event(QEVENT_STOP, NULL);
}
+ bdrv_drain_all();
+ ret = bdrv_flush_all();
+
return ret;
}
@@ -652,6 +653,7 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
wi.func = func;
wi.data = data;
+ wi.free = false;
if (cpu->queued_work_first == NULL) {
cpu->queued_work_first = &wi;
} else {
@@ -670,6 +672,31 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
}
}
+void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
+{
+ struct qemu_work_item *wi;
+
+ if (qemu_cpu_is_self(cpu)) {
+ func(data);
+ return;
+ }
+
+ wi = g_malloc0(sizeof(struct qemu_work_item));
+ wi->func = func;
+ wi->data = data;
+ wi->free = true;
+ if (cpu->queued_work_first == NULL) {
+ cpu->queued_work_first = wi;
+ } else {
+ cpu->queued_work_last->next = wi;
+ }
+ cpu->queued_work_last = wi;
+ wi->next = NULL;
+ wi->done = false;
+
+ qemu_cpu_kick(cpu);
+}
+
static void flush_queued_work(CPUState *cpu)
{
struct qemu_work_item *wi;
@@ -682,6 +709,9 @@ static void flush_queued_work(CPUState *cpu)
cpu->queued_work_first = wi->next;
wi->func(wi->data);
wi->done = true;
+ if (wi->free) {
+ g_free(wi);
+ }
}
cpu->queued_work_last = NULL;
qemu_cond_broadcast(&qemu_work_cond);
@@ -1097,7 +1127,9 @@ int vm_stop_force_state(RunState state)
return vm_stop(state);
} else {
runstate_set(state);
- return 0;
+ /* Make sure to return an error if the flush in a previous vm_stop()
+ * failed. */
+ return bdrv_flush_all();
}
}
@@ -1154,7 +1186,7 @@ static void tcg_exec_all(void)
CPUArchState *env = cpu->env_ptr;
qemu_clock_enable(vm_clock,
- (env->singlestep_enabled & SSTEP_NOTIMER) == 0);
+ (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
if (cpu_can_run(cpu)) {
r = tcg_cpu_exec(env);
@@ -1253,7 +1285,6 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename,
{
FILE *f;
uint32_t l;
- CPUArchState *env;
CPUState *cpu;
uint8_t buf[1024];
@@ -1267,7 +1298,6 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename,
"a CPU number");
return;
}
- env = cpu->env_ptr;
f = fopen(filename, "wb");
if (!f) {
@@ -1279,7 +1309,7 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename,
l = sizeof(buf);
if (l > size)
l = size;
- cpu_memory_rw_debug(env, addr, buf, l, 0);
+ cpu_memory_rw_debug(cpu, addr, buf, l, 0);
if (fwrite(buf, 1, l, f) != l) {
error_set(errp, QERR_IO_ERROR);
goto exit;
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
index 18e5337a77..bc07600f96 100644
--- a/default-configs/alpha-softmmu.mak
+++ b/default-configs/alpha-softmmu.mak
@@ -14,3 +14,4 @@ CONFIG_VMWARE_VGA=y
CONFIG_IDE_CMD646=y
CONFIG_I8259=y
CONFIG_MC146818RTC=y
+CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index b443702b87..926709ae52 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -3,7 +3,6 @@
include pci.mak
include sound.mak
include usb.mak
-CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
CONFIG_VGA_PCI=y
@@ -34,3 +33,4 @@ CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_VT82C686=y
+CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index d63895792b..0ef3f09c77 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -3,7 +3,6 @@
include pci.mak
include sound.mak
include usb.mak
-CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
CONFIG_VGA_PCI=y
@@ -34,3 +33,4 @@ CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_VT82C686=y
+CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index c9be3f49ca..60893182b3 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -3,7 +3,6 @@
include pci.mak
include sound.mak
include usb.mak
-CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
CONFIG_VGA_PCI=y
@@ -36,3 +35,4 @@ CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_VT82C686=y
+CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 4f4a449408..cd59e2479a 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -3,7 +3,6 @@
include pci.mak
include sound.mak
include usb.mak
-CONFIG_ISA_MMIO=y
CONFIG_ESP=y
CONFIG_VGA=y
CONFIG_VGA_PCI=y
@@ -34,3 +33,4 @@ CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_VT82C686=y
+CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 73e4cc5f63..eac0b28fb9 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -46,3 +46,4 @@ CONFIG_E500=y
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
# For PReP
CONFIG_MC146818RTC=y
+CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index 6d1933bbf9..7831c2bf57 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -48,4 +48,11 @@ CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
# For pSeries
CONFIG_XICS=$(CONFIG_PSERIES)
# For PReP
+CONFIG_I82378=y
+CONFIG_I8259=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_I82374=y
+CONFIG_I8257=y
CONFIG_MC146818RTC=y
+CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index e3b5e50360..86080a7574 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -41,3 +41,4 @@ CONFIG_E500=y
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
# For PReP
CONFIG_MC146818RTC=y
+CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak
index f6bf62d1c2..8e00390d4f 100644
--- a/default-configs/sh4-softmmu.mak
+++ b/default-configs/sh4-softmmu.mak
@@ -5,7 +5,14 @@ include usb.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y
-CONFIG_ISA_MMIO=y
CONFIG_SH4=y
CONFIG_IDE_MMIO=y
CONFIG_SM501=y
+CONFIG_ISA_TESTDEV=y
+CONFIG_I82378=y
+CONFIG_I8259=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_I82374=y
+CONFIG_I8257=y
+CONFIG_MC146818RTC=y
diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak
index c1d513d099..efdd05842f 100644
--- a/default-configs/sh4eb-softmmu.mak
+++ b/default-configs/sh4eb-softmmu.mak
@@ -5,7 +5,14 @@ include usb.mak
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y
-CONFIG_ISA_MMIO=y
CONFIG_SH4=y
CONFIG_IDE_MMIO=y
CONFIG_SM501=y
+CONFIG_ISA_TESTDEV=y
+CONFIG_I82378=y
+CONFIG_I8259=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_I82374=y
+CONFIG_I8257=y
+CONFIG_MC146818RTC=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index 9b08ee8a20..299c97b715 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -15,3 +15,4 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_CMD646=y
CONFIG_PCI_APB=y
CONFIG_MC146818RTC=y
+CONFIG_ISA_TESTDEV=y
diff --git a/device_tree.c b/device_tree.c
index 10cf3d0b60..ffec99ae29 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -308,3 +308,36 @@ void qemu_devtree_dumpdtb(void *fdt, int size)
exit(g_file_set_contents(dumpdtb, fdt, size, NULL) ? 0 : 1);
}
}
+
+int qemu_devtree_setprop_sized_cells_from_array(void *fdt,
+ const char *node_path,
+ const char *property,
+ int numvalues,
+ uint64_t *values)
+{
+ uint32_t *propcells;
+ uint64_t value;
+ int cellnum, vnum, ncells;
+ uint32_t hival;
+
+ propcells = g_new0(uint32_t, numvalues * 2);
+
+ cellnum = 0;
+ for (vnum = 0; vnum < numvalues; vnum++) {
+ ncells = values[vnum * 2];
+ if (ncells != 1 && ncells != 2) {
+ return -1;
+ }
+ value = values[vnum * 2 + 1];
+ hival = cpu_to_be32(value >> 32);
+ if (ncells > 1) {
+ propcells[cellnum++] = hival;
+ } else if (hival != 0) {
+ return -1;
+ }
+ propcells[cellnum++] = cpu_to_be32(value);
+ }
+
+ return qemu_devtree_setprop(fdt, node_path, property, propcells,
+ cellnum * sizeof(uint32_t));
+}
diff --git a/disas.c b/disas.c
index e51127e540..71007fb6a1 100644
--- a/disas.c
+++ b/disas.c
@@ -39,7 +39,7 @@ target_read_memory (bfd_vma memaddr,
{
CPUDebug *s = container_of(info, CPUDebug, info);
- cpu_memory_rw_debug(s->env, memaddr, myaddr, length, 0);
+ cpu_memory_rw_debug(ENV_GET_CPU(s->env), memaddr, myaddr, length, 0);
return 0;
}
@@ -392,7 +392,7 @@ monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
if (monitor_disas_is_physical) {
cpu_physical_memory_read(memaddr, myaddr, length);
} else {
- cpu_memory_rw_debug(s->env, memaddr,myaddr, length, 0);
+ cpu_memory_rw_debug(ENV_GET_CPU(s->env), memaddr, myaddr, length, 0);
}
return 0;
}
diff --git a/docs/rdma.txt b/docs/rdma.txt
index 45a4b1d50d..45d1c8aab8 100644
--- a/docs/rdma.txt
+++ b/docs/rdma.txt
@@ -35,7 +35,7 @@ memory tracked during each live migration iteration round cannot keep pace
with the rate of dirty memory produced by the workload.
RDMA currently comes in two flavors: both Ethernet based (RoCE, or RDMA
-over Convered Ethernet) as well as Infiniband-based. This implementation of
+over Converged Ethernet) as well as Infiniband-based. This implementation of
migration using RDMA is capable of using both technologies because of
the use of the OpenFabrics OFED software stack that abstracts out the
programming model irrespective of the underlying hardware.
@@ -188,9 +188,9 @@ header portion and a data portion (but together are transmitted
as a single SEND message).
Header:
- * Length (of the data portion, uint32, network byte order)
- * Type (what command to perform, uint32, network byte order)
- * Repeat (Number of commands in data portion, same type only)
+ * Length (of the data portion, uint32, network byte order)
+ * Type (what command to perform, uint32, network byte order)
+ * Repeat (Number of commands in data portion, same type only)
The 'Repeat' field is here to support future multiple page registrations
in a single message without any need to change the protocol itself
@@ -202,17 +202,19 @@ The maximum number of repeats is hard-coded to 4096. This is a conservative
limit based on the maximum size of a SEND message along with emperical
observations on the maximum future benefit of simultaneous page registrations.
-The 'type' field has 10 different command values:
- 1. Unused
- 2. Error (sent to the source during bad things)
- 3. Ready (control-channel is available)
- 4. QEMU File (for sending non-live device state)
- 5. RAM Blocks request (used right after connection setup)
- 6. RAM Blocks result (used right after connection setup)
- 7. Compress page (zap zero page and skip registration)
- 8. Register request (dynamic chunk registration)
- 9. Register result ('rkey' to be used by sender)
- 10. Register finished (registration for current iteration finished)
+The 'type' field has 12 different command values:
+ 1. Unused
+ 2. Error (sent to the source during bad things)
+ 3. Ready (control-channel is available)
+ 4. QEMU File (for sending non-live device state)
+ 5. RAM Blocks request (used right after connection setup)
+ 6. RAM Blocks result (used right after connection setup)
+ 7. Compress page (zap zero page and skip registration)
+ 8. Register request (dynamic chunk registration)
+ 9. Register result ('rkey' to be used by sender)
+ 10. Register finished (registration for current iteration finished)
+ 11. Unregister request (unpin previously registered memory)
+ 12. Unregister finished (confirmation that unpin completed)
A single control message, as hinted above, can contain within the data
portion an array of many commands of the same type. If there is more than
@@ -243,7 +245,7 @@ qemu_rdma_exchange_send(header, data, optional response header & data):
from the receiver to tell us that the receiver
is *ready* for us to transmit some new bytes.
2. Optionally: if we are expecting a response from the command
- (that we have no yet transmitted), let's post an RQ
+ (that we have not yet transmitted), let's post an RQ
work request to receive that data a few moments later.
3. When the READY arrives, librdmacm will
unblock us and we immediately post a RQ work request
@@ -293,8 +295,10 @@ librdmacm provides the user with a 'private data' area to be exchanged
at connection-setup time before any infiniband traffic is generated.
Header:
- * Version (protocol version validated before send/recv occurs), uint32, network byte order
- * Flags (bitwise OR of each capability), uint32, network byte order
+ * Version (protocol version validated before send/recv occurs),
+ uint32, network byte order
+ * Flags (bitwise OR of each capability),
+ uint32, network byte order
There is no data portion of this header right now, so there is
no length field. The maximum size of the 'private data' section
@@ -313,7 +317,7 @@ If the version is invalid, we throw an error.
If the version is new, we only negotiate the capabilities that the
requested version is able to perform and ignore the rest.
-Currently there is only *one* capability in Version #1: dynamic page registration
+Currently there is only one capability in Version #1: dynamic page registration
Finally: Negotiation happens with the Flags field: If the primary-VM
sets a flag, but the destination does not support this capability, it
@@ -326,8 +330,8 @@ QEMUFileRDMA Interface:
QEMUFileRDMA introduces a couple of new functions:
-1. qemu_rdma_get_buffer() (QEMUFileOps rdma_read_ops)
-2. qemu_rdma_put_buffer() (QEMUFileOps rdma_write_ops)
+1. qemu_rdma_get_buffer() (QEMUFileOps rdma_read_ops)
+2. qemu_rdma_put_buffer() (QEMUFileOps rdma_write_ops)
These two functions are very short and simply use the protocol
describe above to deliver bytes without changing the upper-level
@@ -413,3 +417,8 @@ TODO:
the use of KSM and ballooning while using RDMA.
4. Also, some form of balloon-device usage tracking would also
help alleviate some issues.
+5. Move UNREGISTER requests to a separate thread.
+6. Use LRU to provide more fine-grained direction of UNREGISTER
+ requests for unpinning memory in an overcommitted environment.
+7. Expose UNREGISTER support to the user by way of workload-specific
+ hints about application behavior.
diff --git a/exec.c b/exec.c
index c99a8839c5..3ba9525bd3 100644
--- a/exec.c
+++ b/exec.c
@@ -415,14 +415,14 @@ void cpu_exec_init(CPUArchState *env)
#if defined(TARGET_HAS_ICE)
#if defined(CONFIG_USER_ONLY)
-static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
tb_invalidate_phys_page_range(pc, pc + 1, 0);
}
#else
-static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
- tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc) |
+ tb_invalidate_phys_addr(cpu_get_phys_page_debug(cpu, pc) |
(pc & ~TARGET_PAGE_MASK));
}
#endif
@@ -525,15 +525,17 @@ int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags,
bp->flags = flags;
/* keep all GDB-injected breakpoints in front */
- if (flags & BP_GDB)
+ if (flags & BP_GDB) {
QTAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
- else
+ } else {
QTAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
+ }
- breakpoint_invalidate(env, pc);
+ breakpoint_invalidate(ENV_GET_CPU(env), pc);
- if (breakpoint)
+ if (breakpoint) {
*breakpoint = bp;
+ }
return 0;
#else
return -ENOSYS;
@@ -564,7 +566,7 @@ void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint)
#if defined(TARGET_HAS_ICE)
QTAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
- breakpoint_invalidate(env, breakpoint->pc);
+ breakpoint_invalidate(ENV_GET_CPU(env), breakpoint->pc);
g_free(breakpoint);
#endif
@@ -585,14 +587,16 @@ void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
/* enable or disable single step mode. EXCP_DEBUG is returned by the
CPU loop after each instruction */
-void cpu_single_step(CPUArchState *env, int enabled)
+void cpu_single_step(CPUState *cpu, int enabled)
{
#if defined(TARGET_HAS_ICE)
- if (env->singlestep_enabled != enabled) {
- env->singlestep_enabled = enabled;
- if (kvm_enabled())
+ CPUArchState *env = cpu->env_ptr;
+
+ if (cpu->singlestep_enabled != enabled) {
+ cpu->singlestep_enabled = enabled;
+ if (kvm_enabled()) {
kvm_update_guest_debug(env, 0);
- else {
+ } else {
/* must flush all the translated code to avoid inconsistencies */
/* XXX: only flush what is necessary */
tb_flush(env);
@@ -642,6 +646,10 @@ CPUArchState *cpu_copy(CPUArchState *env)
CPUWatchpoint *wp;
#endif
+ /* Reset non arch specific state */
+ cpu_reset(ENV_GET_CPU(new_env));
+
+ /* Copy arch specific state into the new CPU */
memcpy(new_env, env, sizeof(CPUArchState));
/* Clone all break/watchpoints.
@@ -1379,7 +1387,7 @@ static void *qemu_safe_ram_ptr(ram_addr_t addr)
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
* but takes a size argument */
-static void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size)
+static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
{
if (*size == 0) {
return NULL;
@@ -1831,7 +1839,7 @@ MemoryRegion *get_system_io(void)
/* physical memory access (slow version, mainly for debug) */
#if defined(CONFIG_USER_ONLY)
-int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr,
+int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
uint8_t *buf, int len, int is_write)
{
int l, flags;
@@ -1898,14 +1906,10 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
{
- unsigned access_size_min = mr->ops->impl.min_access_size;
- unsigned access_size_max = mr->ops->impl.max_access_size;
+ unsigned access_size_max = mr->ops->valid.max_access_size;
/* Regions are assumed to support 1-4 byte accesses unless
otherwise specified. */
- if (access_size_min == 0) {
- access_size_min = 1;
- }
if (access_size_max == 0) {
access_size_max = 4;
}
@@ -1922,9 +1926,6 @@ static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
if (l > access_size_max) {
l = access_size_max;
}
- /* ??? The users of this function are wrong, not supporting minimums larger
- than the remaining length. C.f. memory.c:access_with_adjusted_size. */
- assert(l >= access_size_min);
return l;
}
@@ -2609,7 +2610,7 @@ void stq_be_phys(hwaddr addr, uint64_t val)
}
/* virtual memory access for debug (includes writing to ROM) */
-int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr,
+int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
uint8_t *buf, int len, int is_write)
{
int l;
@@ -2618,7 +2619,7 @@ int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr,
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
- phys_addr = cpu_get_phys_page_debug(env, page);
+ phys_addr = cpu_get_phys_page_debug(cpu, page);
/* if no physical page mapped, return an error */
if (phys_addr == -1)
return -1;
diff --git a/gdbstub.c b/gdbstub.c
index 0ee82a944f..35ca7c2c1e 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -42,15 +42,16 @@
#include "sysemu/kvm.h"
#include "qemu/bitops.h"
-#ifndef TARGET_CPU_MEMORY_RW_DEBUG
-static inline int target_memory_rw_debug(CPUArchState *env, target_ulong addr,
- uint8_t *buf, int len, int is_write)
+static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
+ uint8_t *buf, int len, bool is_write)
{
- return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ if (cc->memory_rw_debug) {
+ return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
+ }
+ return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
}
-#else
-/* target_memory_rw_debug() defined in cpu.h */
-#endif
enum {
GDB_SIGNAL_0 = 0,
@@ -287,9 +288,9 @@ enum RSState {
RS_CHKSUM2,
};
typedef struct GDBState {
- CPUArchState *c_cpu; /* current CPU for step/continue ops */
- CPUArchState *g_cpu; /* current CPU for other ops */
- CPUArchState *query_cpu; /* for q{f|s}ThreadInfo */
+ CPUState *c_cpu; /* current CPU for step/continue ops */
+ CPUState *g_cpu; /* current CPU for other ops */
+ CPUState *query_cpu; /* for q{f|s}ThreadInfo */
enum RSState state; /* parsing state */
char line_buf[MAX_PACKET_LENGTH];
int line_buf_index;
@@ -1839,7 +1840,7 @@ static const char *get_feature_xml(const char *p, const char **newp)
/* Generate the XML description for this CPU. */
if (!target_xml[0]) {
GDBRegisterState *r;
- CPUArchState *env = first_cpu->env_ptr;
+ CPUState *cpu = first_cpu;
snprintf(target_xml, sizeof(target_xml),
"<?xml version=\"1.0\"?>"
@@ -1848,7 +1849,7 @@ static const char *get_feature_xml(const char *p, const char **newp)
"<xi:include href=\"%s\"/>",
GDB_CORE_XML);
- for (r = env->gdb_regs; r; r = r->next) {
+ for (r = cpu->gdb_regs; r; r = r->next) {
pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
pstrcat(target_xml, sizeof(target_xml), r->xml);
pstrcat(target_xml, sizeof(target_xml), "\"/>");
@@ -1866,14 +1867,15 @@ static const char *get_feature_xml(const char *p, const char **newp)
}
#endif
-static int gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int reg)
+static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg)
{
+ CPUArchState *env = cpu->env_ptr;
GDBRegisterState *r;
if (reg < NUM_CORE_REGS)
return cpu_gdb_read_register(env, mem_buf, reg);
- for (r = env->gdb_regs; r; r = r->next) {
+ for (r = cpu->gdb_regs; r; r = r->next) {
if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
return r->get_reg(env, mem_buf, reg - r->base_reg);
}
@@ -1881,14 +1883,15 @@ static int gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int reg)
return 0;
}
-static int gdb_write_register(CPUArchState *env, uint8_t *mem_buf, int reg)
+static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
{
+ CPUArchState *env = cpu->env_ptr;
GDBRegisterState *r;
if (reg < NUM_CORE_REGS)
return cpu_gdb_write_register(env, mem_buf, reg);
- for (r = env->gdb_regs; r; r = r->next) {
+ for (r = cpu->gdb_regs; r; r = r->next) {
if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
return r->set_reg(env, mem_buf, reg - r->base_reg);
}
@@ -1903,15 +1906,15 @@ static int gdb_write_register(CPUArchState *env, uint8_t *mem_buf, int reg)
gdb reading a CPU register, and set_reg is gdb modifying a CPU register.
*/
-void gdb_register_coprocessor(CPUArchState * env,
- gdb_reg_cb get_reg, gdb_reg_cb set_reg,
- int num_regs, const char *xml, int g_pos)
+void gdb_register_coprocessor(CPUState *cpu,
+ gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+ int num_regs, const char *xml, int g_pos)
{
GDBRegisterState *s;
GDBRegisterState **p;
static int last_reg = NUM_CORE_REGS;
- p = &env->gdb_regs;
+ p = &cpu->gdb_regs;
while (*p) {
/* Check for duplicates. */
if (strcmp((*p)->xml, xml) == 0)
@@ -1954,8 +1957,9 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
CPUArchState *env;
int err = 0;
- if (kvm_enabled())
+ if (kvm_enabled()) {
return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+ }
switch (type) {
case GDB_BREAKPOINT_SW:
@@ -1991,8 +1995,9 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
CPUArchState *env;
int err = 0;
- if (kvm_enabled())
+ if (kvm_enabled()) {
return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+ }
switch (type) {
case GDB_BREAKPOINT_SW:
@@ -2027,7 +2032,7 @@ static void gdb_breakpoint_remove_all(void)
CPUArchState *env;
if (kvm_enabled()) {
- kvm_remove_all_breakpoints(ENV_GET_CPU(gdbserver_state->c_cpu));
+ kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
return;
}
@@ -2042,49 +2047,22 @@ static void gdb_breakpoint_remove_all(void)
static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
{
- cpu_synchronize_state(ENV_GET_CPU(s->c_cpu));
-#if defined(TARGET_I386)
- s->c_cpu->eip = pc;
-#elif defined (TARGET_PPC)
- s->c_cpu->nip = pc;
-#elif defined (TARGET_SPARC)
- s->c_cpu->pc = pc;
- s->c_cpu->npc = pc + 4;
-#elif defined (TARGET_ARM)
- s->c_cpu->regs[15] = pc;
-#elif defined (TARGET_SH4)
- s->c_cpu->pc = pc;
-#elif defined (TARGET_MIPS)
- s->c_cpu->active_tc.PC = pc & ~(target_ulong)1;
- if (pc & 1) {
- s->c_cpu->hflags |= MIPS_HFLAG_M16;
- } else {
- s->c_cpu->hflags &= ~(MIPS_HFLAG_M16);
+ CPUState *cpu = s->c_cpu;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ cpu_synchronize_state(cpu);
+ if (cc->set_pc) {
+ cc->set_pc(cpu, pc);
}
-#elif defined (TARGET_MICROBLAZE)
- s->c_cpu->sregs[SR_PC] = pc;
-#elif defined(TARGET_OPENRISC)
- s->c_cpu->pc = pc;
-#elif defined (TARGET_CRIS)
- s->c_cpu->pc = pc;
-#elif defined (TARGET_ALPHA)
- s->c_cpu->pc = pc;
-#elif defined (TARGET_S390X)
- s->c_cpu->psw.addr = pc;
-#elif defined (TARGET_LM32)
- s->c_cpu->pc = pc;
-#elif defined(TARGET_XTENSA)
- s->c_cpu->pc = pc;
-#endif
}
-static CPUArchState *find_cpu(uint32_t thread_id)
+static CPUState *find_cpu(uint32_t thread_id)
{
CPUState *cpu;
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
if (cpu_index(cpu) == thread_id) {
- return cpu->env_ptr;
+ return cpu;
}
}
@@ -2093,7 +2071,10 @@ static CPUArchState *find_cpu(uint32_t thread_id)
static int gdb_handle_packet(GDBState *s, const char *line_buf)
{
+#ifdef TARGET_XTENSA
CPUArchState *env;
+#endif
+ CPUState *cpu;
const char *p;
uint32_t thread;
int ch, reg_size, type, res;
@@ -2111,7 +2092,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
case '?':
/* TODO: Make this return the correct value for user-mode. */
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
- cpu_index(ENV_GET_CPU(s->c_cpu)));
+ cpu_index(s->c_cpu));
put_packet(s, buf);
/* Remove all the breakpoints when this query is issued,
* because gdb is doing and initial connect and the state
@@ -2173,12 +2154,12 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
}
if (res) {
if (res_thread != -1 && res_thread != 0) {
- env = find_cpu(res_thread);
- if (env == NULL) {
+ cpu = find_cpu(res_thread);
+ if (cpu == NULL) {
put_packet(s, "E22");
break;
}
- s->c_cpu = env;
+ s->c_cpu = cpu;
}
if (res == 's') {
cpu_single_step(s->c_cpu, sstep_flags);
@@ -2239,8 +2220,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
}
break;
case 'g':
- cpu_synchronize_state(ENV_GET_CPU(s->g_cpu));
- env = s->g_cpu;
+ cpu_synchronize_state(s->g_cpu);
+#ifdef TARGET_XTENSA
+ env = s->g_cpu->env_ptr;
+#endif
len = 0;
for (addr = 0; addr < num_g_regs; addr++) {
reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
@@ -2250,8 +2233,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
put_packet(s, buf);
break;
case 'G':
- cpu_synchronize_state(ENV_GET_CPU(s->g_cpu));
- env = s->g_cpu;
+ cpu_synchronize_state(s->g_cpu);
+#ifdef TARGET_XTENSA
+ env = s->g_cpu->env_ptr;
+#endif
registers = mem_buf;
len = strlen(p) / 2;
hextomem((uint8_t *)registers, p, len);
@@ -2267,7 +2252,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
if (*p == ',')
p++;
len = strtoull(p, NULL, 16);
- if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
+ if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, false) != 0) {
put_packet (s, "E14");
} else {
memtohex(buf, mem_buf, len);
@@ -2282,7 +2267,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
if (*p == ':')
p++;
hextomem(mem_buf, p, len);
- if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) {
+ if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len,
+ true) != 0) {
put_packet(s, "E14");
} else {
put_packet(s, "OK");
@@ -2341,18 +2327,18 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
put_packet(s, "OK");
break;
}
- env = find_cpu(thread);
- if (env == NULL) {
+ cpu = find_cpu(thread);
+ if (cpu == NULL) {
put_packet(s, "E22");
break;
}
switch (type) {
case 'c':
- s->c_cpu = env;
+ s->c_cpu = cpu;
put_packet(s, "OK");
break;
case 'g':
- s->g_cpu = env;
+ s->g_cpu = cpu;
put_packet(s, "OK");
break;
default:
@@ -2362,9 +2348,9 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
break;
case 'T':
thread = strtoull(p, (char **)&p, 16);
- env = find_cpu(thread);
+ cpu = find_cpu(thread);
- if (env != NULL) {
+ if (cpu != NULL) {
put_packet(s, "OK");
} else {
put_packet(s, "E22");
@@ -2401,23 +2387,21 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
put_packet(s, "QC1");
break;
} else if (strcmp(p,"fThreadInfo") == 0) {
- s->query_cpu = first_cpu->env_ptr;
+ s->query_cpu = first_cpu;
goto report_cpuinfo;
} else if (strcmp(p,"sThreadInfo") == 0) {
report_cpuinfo:
if (s->query_cpu) {
- snprintf(buf, sizeof(buf), "m%x",
- cpu_index(ENV_GET_CPU(s->query_cpu)));
+ snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu));
put_packet(s, buf);
- s->query_cpu = ENV_GET_CPU(s->query_cpu)->next_cpu->env_ptr;
+ s->query_cpu = s->query_cpu->next_cpu;
} else
put_packet(s, "l");
break;
} else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
thread = strtoull(p+16, (char **)&p, 16);
- env = find_cpu(thread);
- if (env != NULL) {
- CPUState *cpu = ENV_GET_CPU(env);
+ cpu = find_cpu(thread);
+ if (cpu != NULL) {
cpu_synchronize_state(cpu);
len = snprintf((char *)mem_buf, sizeof(mem_buf),
"CPU#%d [%s]", cpu->cpu_index,
@@ -2429,7 +2413,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
}
#ifdef CONFIG_USER_ONLY
else if (strncmp(p, "Offsets", 7) == 0) {
- TaskState *ts = s->c_cpu->opaque;
+ CPUArchState *env = s->c_cpu->env_ptr;
+ TaskState *ts = env->opaque;
snprintf(buf, sizeof(buf),
"Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
@@ -2519,18 +2504,16 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
void gdb_set_stop_cpu(CPUState *cpu)
{
- CPUArchState *env = cpu->env_ptr;
-
- gdbserver_state->c_cpu = env;
- gdbserver_state->g_cpu = env;
+ gdbserver_state->c_cpu = cpu;
+ gdbserver_state->g_cpu = cpu;
}
#ifndef CONFIG_USER_ONLY
static void gdb_vm_state_change(void *opaque, int running, RunState state)
{
GDBState *s = gdbserver_state;
- CPUArchState *env = s->c_cpu;
- CPUState *cpu = ENV_GET_CPU(env);
+ CPUArchState *env = s->c_cpu->env_ptr;
+ CPUState *cpu = s->c_cpu;
char buf[256];
const char *type;
int ret;
@@ -2598,7 +2581,7 @@ send_packet:
put_packet(s, buf);
/* disable single step if it was enabled */
- cpu_single_step(env, 0);
+ cpu_single_step(cpu, 0);
}
#endif
@@ -2668,7 +2651,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
is still in the running state, which can cause packets to be dropped
and state transition 'T' packets to be sent while the syscall is still
being processed. */
- cpu_exit(ENV_GET_CPU(s->c_cpu));
+ cpu_exit(s->c_cpu);
#endif
}
@@ -2789,66 +2772,67 @@ gdb_queuesig (void)
}
int
-gdb_handlesig (CPUArchState *env, int sig)
+gdb_handlesig(CPUState *cpu, int sig)
{
- GDBState *s;
- char buf[256];
- int n;
+ CPUArchState *env = cpu->env_ptr;
+ GDBState *s;
+ char buf[256];
+ int n;
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
- return sig;
+ s = gdbserver_state;
+ if (gdbserver_fd < 0 || s->fd < 0) {
+ return sig;
+ }
- /* disable single step if it was enabled */
- cpu_single_step(env, 0);
- tb_flush(env);
+ /* disable single step if it was enabled */
+ cpu_single_step(cpu, 0);
+ tb_flush(env);
- if (sig != 0)
- {
- snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig));
- put_packet(s, buf);
- }
- /* put_packet() might have detected that the peer terminated the
- connection. */
- if (s->fd < 0)
- return sig;
-
- sig = 0;
- s->state = RS_IDLE;
- s->running_state = 0;
- while (s->running_state == 0) {
- n = read (s->fd, buf, 256);
- if (n > 0)
- {
- int i;
+ if (sig != 0) {
+ snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb(sig));
+ put_packet(s, buf);
+ }
+ /* put_packet() might have detected that the peer terminated the
+ connection. */
+ if (s->fd < 0) {
+ return sig;
+ }
- for (i = 0; i < n; i++)
- gdb_read_byte (s, buf[i]);
- }
- else if (n == 0 || errno != EAGAIN)
- {
- /* XXX: Connection closed. Should probably wait for another
- connection before continuing. */
- return sig;
+ sig = 0;
+ s->state = RS_IDLE;
+ s->running_state = 0;
+ while (s->running_state == 0) {
+ n = read(s->fd, buf, 256);
+ if (n > 0) {
+ int i;
+
+ for (i = 0; i < n; i++) {
+ gdb_read_byte(s, buf[i]);
+ }
+ } else if (n == 0 || errno != EAGAIN) {
+ /* XXX: Connection closed. Should probably wait for another
+ connection before continuing. */
+ return sig;
}
- }
- sig = s->signal;
- s->signal = 0;
- return sig;
+ }
+ sig = s->signal;
+ s->signal = 0;
+ return sig;
}
/* Tell the remote gdb that the process has exited due to SIG. */
void gdb_signalled(CPUArchState *env, int sig)
{
- GDBState *s;
- char buf[4];
+ GDBState *s;
+ char buf[4];
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
- return;
+ s = gdbserver_state;
+ if (gdbserver_fd < 0 || s->fd < 0) {
+ return;
+ }
- snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
- put_packet(s, buf);
+ snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb(sig));
+ put_packet(s, buf);
}
static void gdb_accept(void)
@@ -2876,8 +2860,8 @@ static void gdb_accept(void)
socket_set_nodelay(fd);
s = g_malloc0(sizeof(GDBState));
- s->c_cpu = first_cpu->env_ptr;
- s->g_cpu = first_cpu->env_ptr;
+ s->c_cpu = first_cpu;
+ s->g_cpu = first_cpu;
s->fd = fd;
gdb_has_xml = 0;
@@ -3061,8 +3045,8 @@ int gdbserver_start(const char *device)
mon_chr = s->mon_chr;
memset(s, 0, sizeof(GDBState));
}
- s->c_cpu = first_cpu->env_ptr;
- s->g_cpu = first_cpu->env_ptr;
+ s->c_cpu = first_cpu;
+ s->g_cpu = first_cpu;
s->chr = chr;
s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr;
diff --git a/hmp.c b/hmp.c
index dc4d8d453f..c45514b6b1 100644
--- a/hmp.c
+++ b/hmp.c
@@ -164,6 +164,10 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "downtime: %" PRIu64 " milliseconds\n",
info->downtime);
}
+ if (info->has_setup_time) {
+ monitor_printf(mon, "setup: %" PRIu64 " milliseconds\n",
+ info->setup_time);
+ }
}
if (info->has_ram) {
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 948ea8795b..c88569061c 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -64,7 +64,9 @@ typedef struct CPUStatus {
} CPUStatus;
typedef struct PIIX4PMState {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
MemoryRegion io;
MemoryRegion io_gpe;
@@ -96,6 +98,11 @@ typedef struct PIIX4PMState {
Notifier cpu_added_notifier;
} PIIX4PMState;
+#define TYPE_PIIX4_PM "PIIX4_PM"
+
+#define PIIX4_PM(obj) \
+ OBJECT_CHECK(PIIX4PMState, (obj), TYPE_PIIX4_PM)
+
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
PCIBus *bus, PIIX4PMState *s);
@@ -130,11 +137,12 @@ static void pm_tmr_timer(ACPIREGS *ar)
static void apm_ctrl_changed(uint32_t val, void *arg)
{
PIIX4PMState *s = arg;
+ PCIDevice *d = PCI_DEVICE(s);
/* ACPI specs 3.0, 4.7.2.5 */
acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE);
- if (s->dev.config[0x5b] & (1 << 1)) {
+ if (d->config[0x5b] & (1 << 1)) {
if (s->smi_irq) {
qemu_irq_raise(s->smi_irq);
}
@@ -143,24 +151,27 @@ static void apm_ctrl_changed(uint32_t val, void *arg)
static void pm_io_space_update(PIIX4PMState *s)
{
+ PCIDevice *d = PCI_DEVICE(s);
uint32_t pm_io_base;
- pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
+ pm_io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40));
pm_io_base &= 0xffc0;
memory_region_transaction_begin();
- memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1);
+ memory_region_set_enabled(&s->io, d->config[0x80] & 1);
memory_region_set_address(&s->io, pm_io_base);
memory_region_transaction_commit();
}
static void smbus_io_space_update(PIIX4PMState *s)
{
- s->smb_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x90));
+ PCIDevice *d = PCI_DEVICE(s);
+
+ s->smb_io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x90));
s->smb_io_base &= 0xffc0;
memory_region_transaction_begin();
- memory_region_set_enabled(&s->smb.io, s->dev.config[0xd2] & 1);
+ memory_region_set_enabled(&s->smb.io, d->config[0xd2] & 1);
memory_region_set_address(&s->smb.io, s->smb_io_base);
memory_region_transaction_commit();
}
@@ -239,7 +250,7 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
int ret, i;
uint16_t temp;
- ret = pci_device_load(&s->dev, f);
+ ret = pci_device_load(PCI_DEVICE(s), f);
if (ret < 0) {
return ret;
}
@@ -283,7 +294,7 @@ static const VMStateDescription vmstate_acpi = {
.load_state_old = acpi_load_old,
.post_load = vmstate_acpi_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
+ VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState),
VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
@@ -300,7 +311,7 @@ static const VMStateDescription vmstate_acpi = {
static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
{
BusChild *kid, *next;
- BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
+ BusState *bus = qdev_get_parent_bus(DEVICE(s));
int slot = ffs(slots) - 1;
bool slot_free = true;
@@ -326,8 +337,7 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
static void piix4_update_hotplug(PIIX4PMState *s)
{
- PCIDevice *dev = &s->dev;
- BusState *bus = qdev_get_parent_bus(&dev->qdev);
+ BusState *bus = qdev_get_parent_bus(DEVICE(s));
BusChild *kid, *next;
/* Execute any pending removes during reset */
@@ -355,7 +365,8 @@ static void piix4_update_hotplug(PIIX4PMState *s)
static void piix4_reset(void *opaque)
{
PIIX4PMState *s = opaque;
- uint8_t *pci_conf = s->dev.config;
+ PCIDevice *d = PCI_DEVICE(s);
+ uint8_t *pci_conf = d->config;
pci_conf[0x58] = 0;
pci_conf[0x59] = 0;
@@ -383,10 +394,11 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
{
PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
- MemoryRegion *io_as = pci_address_space_io(&s->dev);
+ PCIDevice *d = PCI_DEVICE(s);
+ MemoryRegion *io_as = pci_address_space_io(d);
uint8_t *pci_conf;
- pci_conf = s->dev.config;
+ pci_conf = d->config;
pci_conf[0x5f] = 0x10 |
(memory_region_present(io_as, 0x378) ? 0x80 : 0);
pci_conf[0x63] = 0x60;
@@ -396,10 +408,10 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
static int piix4_pm_initfn(PCIDevice *dev)
{
- PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
+ PIIX4PMState *s = PIIX4_PM(dev);
uint8_t *pci_conf;
- pci_conf = s->dev.config;
+ pci_conf = dev->config;
pci_conf[0x06] = 0x80;
pci_conf[0x07] = 0x02;
pci_conf[0x09] = 0x00;
@@ -419,7 +431,7 @@ static int piix4_pm_initfn(PCIDevice *dev)
pci_conf[0x90] = s->smb_io_base | 1;
pci_conf[0x91] = s->smb_io_base >> 8;
pci_conf[0xd2] = 0x09;
- pm_smbus_init(&s->dev.qdev, &s->smb);
+ pm_smbus_init(DEVICE(dev), &s->smb);
memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
memory_region_add_subregion(pci_address_space_io(dev),
s->smb_io_base, &s->smb.io);
@@ -450,18 +462,18 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq, qemu_irq smi_irq,
int kvm_enabled, FWCfgState *fw_cfg)
{
- PCIDevice *dev;
+ DeviceState *dev;
PIIX4PMState *s;
- dev = pci_create(bus, devfn, "PIIX4_PM");
- qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
+ dev = DEVICE(pci_create(bus, devfn, TYPE_PIIX4_PM));
+ qdev_prop_set_uint32(dev, "smb_io_base", smb_io_base);
- s = DO_UPCAST(PIIX4PMState, dev, dev);
+ s = PIIX4_PM(dev);
s->irq = sci_irq;
s->smi_irq = smi_irq;
s->kvm_enabled = kvm_enabled;
- qdev_init_nofail(&dev->qdev);
+ qdev_init_nofail(dev);
if (fw_cfg) {
uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
@@ -501,7 +513,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo piix4_pm_info = {
- .name = "PIIX4_PM",
+ .name = TYPE_PIIX4_PM,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX4PMState),
.class_init = piix4_pm_class_init,
@@ -679,7 +691,7 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
"acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
&s->io_pci);
- pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
+ pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
qemu_for_each_cpu(piix4_init_cpu_status, &s->gpe_cpu);
memory_region_init_io(&s->io_cpu, OBJECT(s), &cpu_hotplug_ops, s,
@@ -705,8 +717,7 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state)
{
int slot = PCI_SLOT(dev->devfn);
- PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
- PCI_DEVICE(qdev));
+ PIIX4PMState *s = PIIX4_PM(qdev);
/* Don't send event when device is enabled during qemu machine creation:
* it is present on boot, no hotplug event is necessary. We do send an
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index 3d7a1cd8e8..b7fb04406c 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -693,7 +693,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
AlphaCPU *cpu = cpus[i];
s->cchip.cpu[i] = cpu;
if (cpu != NULL) {
- cpu->alarm_timer = qemu_new_timer_ns(rtc_clock,
+ cpu->alarm_timer = qemu_new_timer_ns(vm_clock,
typhoon_alarm_timer,
(void *)((uintptr_t)s + i));
}
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index a2e4032f42..2cbeefdcba 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -227,12 +227,10 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
{
- uint32_t *mem_reg_property;
- uint32_t mem_reg_propsize;
void *fdt = NULL;
char *filename;
int size, rc;
- uint32_t acells, scells, hival;
+ uint32_t acells, scells;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename);
if (!filename) {
@@ -255,29 +253,18 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
goto fail;
}
- mem_reg_propsize = acells + scells;
- mem_reg_property = g_new0(uint32_t, mem_reg_propsize);
- mem_reg_property[acells - 1] = cpu_to_be32(binfo->loader_start);
- hival = cpu_to_be32(binfo->loader_start >> 32);
- if (acells > 1) {
- mem_reg_property[acells - 2] = hival;
- } else if (hival != 0) {
- fprintf(stderr, "qemu: dtb file not compatible with "
- "RAM start address > 4GB\n");
- goto fail;
- }
- mem_reg_property[acells + scells - 1] = cpu_to_be32(binfo->ram_size);
- hival = cpu_to_be32(binfo->ram_size >> 32);
- if (scells > 1) {
- mem_reg_property[acells + scells - 2] = hival;
- } else if (hival != 0) {
+ if (scells < 2 && binfo->ram_size >= (1ULL << 32)) {
+ /* This is user error so deserves a friendlier error message
+ * than the failure of setprop_sized_cells would provide
+ */
fprintf(stderr, "qemu: dtb file not compatible with "
"RAM size > 4GB\n");
goto fail;
}
- rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
- mem_reg_propsize * sizeof(uint32_t));
+ rc = qemu_devtree_setprop_sized_cells(fdt, "/memory", "reg",
+ acells, binfo->loader_start,
+ scells, binfo->ram_size);
if (rc < 0) {
fprintf(stderr, "couldn't set /memory/reg\n");
goto fail;
@@ -307,6 +294,11 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
goto fail;
}
}
+
+ if (binfo->modify_dtb) {
+ binfo->modify_dtb(binfo, fdt);
+ }
+
qemu_devtree_dumpdtb(fdt, size);
cpu_physical_memory_write(addr, fdt, size);
@@ -419,10 +411,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
info->entry = entry;
if (is_linux) {
if (info->initrd_filename) {
- initrd_size = load_image_targphys(info->initrd_filename,
- info->initrd_start,
- info->ram_size -
- info->initrd_start);
+ initrd_size = load_ramdisk(info->initrd_filename,
+ info->initrd_start,
+ info->ram_size -
+ info->initrd_start);
+ if (initrd_size < 0) {
+ initrd_size = load_image_targphys(info->initrd_filename,
+ info->initrd_start,
+ info->ram_size -
+ info->initrd_start);
+ }
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initrd '%s'\n",
info->initrd_filename);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 7d1b8233cd..9586e3880e 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -31,12 +31,17 @@
#include "exec/address-spaces.h"
#include "sysemu/blockdev.h"
#include "hw/block/flash.h"
+#include "sysemu/device_tree.h"
+#include <libfdt.h>
#define VEXPRESS_BOARD_ID 0x8e0
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)
-static struct arm_boot_info vexpress_binfo;
+/* Number of virtio transports to create (0..8; limited by
+ * number of available IRQ lines).
+ */
+#define NUM_VIRTIO_TRANSPORTS 4
/* Address maps for peripherals:
* the Versatile Express motherboard has two possible maps,
@@ -73,6 +78,7 @@ enum {
VE_ETHERNET,
VE_USB,
VE_DAPROM,
+ VE_VIRTIO,
};
static hwaddr motherboard_legacy_map[] = {
@@ -91,6 +97,7 @@ static hwaddr motherboard_legacy_map[] = {
[VE_WDT] = 0x1000f000,
[VE_TIMER01] = 0x10011000,
[VE_TIMER23] = 0x10012000,
+ [VE_VIRTIO] = 0x10013000,
[VE_SERIALDVI] = 0x10016000,
[VE_RTC] = 0x10017000,
[VE_COMPACTFLASH] = 0x1001a000,
@@ -137,6 +144,7 @@ static hwaddr motherboard_aseries_map[] = {
[VE_WDT] = 0x1c0f0000,
[VE_TIMER01] = 0x1c110000,
[VE_TIMER23] = 0x1c120000,
+ [VE_VIRTIO] = 0x1c130000,
[VE_SERIALDVI] = 0x1c160000,
[VE_RTC] = 0x1c170000,
[VE_COMPACTFLASH] = 0x1c1a0000,
@@ -153,6 +161,7 @@ typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
qemu_irq *pic);
struct VEDBoardInfo {
+ struct arm_boot_info bootinfo;
const hwaddr *motherboard_map;
hwaddr loader_start;
const hwaddr gic_cpu_if_addr;
@@ -272,7 +281,7 @@ static const uint32_t a9_clocks[] = {
66670000, /* Test chip reference clock: 66.67MHz */
};
-static const VEDBoardInfo a9_daughterboard = {
+static VEDBoardInfo a9_daughterboard = {
.motherboard_map = motherboard_legacy_map,
.loader_start = 0x60000000,
.gic_cpu_if_addr = 0x1e000100,
@@ -384,7 +393,7 @@ static const uint32_t a15_clocks[] = {
40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */
};
-static const VEDBoardInfo a15_daughterboard = {
+static VEDBoardInfo a15_daughterboard = {
.motherboard_map = motherboard_aseries_map,
.loader_start = 0x80000000,
.gic_cpu_if_addr = 0x2c002000,
@@ -396,7 +405,86 @@ static const VEDBoardInfo a15_daughterboard = {
.init = a15_daughterboard_init,
};
-static void vexpress_common_init(const VEDBoardInfo *daughterboard,
+static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells,
+ hwaddr addr, hwaddr size, uint32_t intc,
+ int irq)
+{
+ /* Add a virtio_mmio node to the device tree blob:
+ * virtio_mmio@ADDRESS {
+ * compatible = "virtio,mmio";
+ * reg = <ADDRESS, SIZE>;
+ * interrupt-parent = <&intc>;
+ * interrupts = <0, irq, 1>;
+ * }
+ * (Note that the format of the interrupts property is dependent on the
+ * interrupt controller that interrupt-parent points to; these are for
+ * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.)
+ */
+ int rc;
+ char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr);
+
+ rc = qemu_devtree_add_subnode(fdt, nodename);
+ rc |= qemu_devtree_setprop_string(fdt, nodename,
+ "compatible", "virtio,mmio");
+ rc |= qemu_devtree_setprop_sized_cells(fdt, nodename, "reg",
+ acells, addr, scells, size);
+ qemu_devtree_setprop_cells(fdt, nodename, "interrupt-parent", intc);
+ qemu_devtree_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1);
+ g_free(nodename);
+ if (rc) {
+ return -1;
+ }
+ return 0;
+}
+
+static uint32_t find_int_controller(void *fdt)
+{
+ /* Find the FDT node corresponding to the interrupt controller
+ * for virtio-mmio devices. We do this by scanning the fdt for
+ * a node with the right compatibility, since we know there is
+ * only one GIC on a vexpress board.
+ * We return the phandle of the node, or 0 if none was found.
+ */
+ const char *compat = "arm,cortex-a9-gic";
+ int offset;
+
+ offset = fdt_node_offset_by_compatible(fdt, -1, compat);
+ if (offset >= 0) {
+ return fdt_get_phandle(fdt, offset);
+ }
+ return 0;
+}
+
+static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
+{
+ uint32_t acells, scells, intc;
+ const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info;
+
+ acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells");
+ scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells");
+ intc = find_int_controller(fdt);
+ if (!intc) {
+ /* Not fatal, we just won't provide virtio. This will
+ * happen with older device tree blobs.
+ */
+ fprintf(stderr, "QEMU: warning: couldn't find interrupt controller in "
+ "dtb; will not include virtio-mmio devices in the dtb.\n");
+ } else {
+ int i;
+ const hwaddr *map = daughterboard->motherboard_map;
+
+ /* We iterate backwards here because adding nodes
+ * to the dtb puts them in last-first.
+ */
+ for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
+ add_virtio_mmio_node(fdt, acells, scells,
+ map[VE_VIRTIO] + 0x200 * i,
+ 0x200, intc, 40 + i);
+ }
+ }
+}
+
+static void vexpress_common_init(VEDBoardInfo *daughterboard,
QEMUMachineInitArgs *args)
{
DeviceState *dev, *sysctl, *pl041;
@@ -524,17 +612,27 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
/* VE_DAPROM: not modelled */
- vexpress_binfo.ram_size = args->ram_size;
- vexpress_binfo.kernel_filename = args->kernel_filename;
- vexpress_binfo.kernel_cmdline = args->kernel_cmdline;
- vexpress_binfo.initrd_filename = args->initrd_filename;
- vexpress_binfo.nb_cpus = smp_cpus;
- vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
- vexpress_binfo.loader_start = daughterboard->loader_start;
- vexpress_binfo.smp_loader_start = map[VE_SRAM];
- vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
- vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
- arm_load_kernel(ARM_CPU(first_cpu), &vexpress_binfo);
+ /* Create mmio transports, so the user can create virtio backends
+ * (which will be automatically plugged in to the transports). If
+ * no backend is created the transport will just sit harmlessly idle.
+ */
+ for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
+ sysbus_create_simple("virtio-mmio", map[VE_VIRTIO] + 0x200 * i,
+ pic[40 + i]);
+ }
+
+ daughterboard->bootinfo.ram_size = args->ram_size;
+ daughterboard->bootinfo.kernel_filename = args->kernel_filename;
+ daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline;
+ daughterboard->bootinfo.initrd_filename = args->initrd_filename;
+ daughterboard->bootinfo.nb_cpus = smp_cpus;
+ daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID;
+ daughterboard->bootinfo.loader_start = daughterboard->loader_start;
+ daughterboard->bootinfo.smp_loader_start = map[VE_SRAM];
+ daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
+ daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
+ daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
+ arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
}
static void vexpress_a9_init(QEMUMachineInitArgs *args)
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 03566650c6..2faed43127 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -537,7 +537,7 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
/* Clean up guest notifier (irq) */
k->set_guest_notifiers(qbus->parent, 1, false);
- vring_teardown(&s->vring);
+ vring_teardown(&s->vring, s->vdev, 0);
s->started = false;
s->stopping = false;
}
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index cdc00e59c5..d32f6ba411 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -544,8 +544,14 @@ struct FDCtrl {
uint8_t timer1;
};
+#define TYPE_SYSBUS_FDC "sysbus-fdc"
+#define SYSBUS_FDC(obj) OBJECT_CHECK(FDCtrlSysBus, (obj), TYPE_SYSBUS_FDC)
+
typedef struct FDCtrlSysBus {
- SysBusDevice busdev;
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
struct FDCtrl state;
} FDCtrlSysBus;
@@ -773,7 +779,7 @@ static const VMStateDescription vmstate_fdc = {
static void fdctrl_external_reset_sysbus(DeviceState *d)
{
- FDCtrlSysBus *sys = container_of(d, FDCtrlSysBus, busdev.qdev);
+ FDCtrlSysBus *sys = SYSBUS_FDC(d);
FDCtrl *s = &sys->state;
fdctrl_reset(s, 0);
@@ -1991,7 +1997,7 @@ static const BlockDevOps fdctrl_block_ops = {
};
/* Init functions */
-static int fdctrl_connect_drives(FDCtrl *fdctrl)
+static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
{
unsigned int i;
FDrive *drive;
@@ -2002,12 +2008,12 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
if (drive->bs) {
if (bdrv_get_on_error(drive->bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
- error_report("fdc doesn't support drive option werror");
- return -1;
+ error_setg(errp, "fdc doesn't support drive option werror");
+ return;
}
if (bdrv_get_on_error(drive->bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
- error_report("fdc doesn't support drive option rerror");
- return -1;
+ error_setg(errp, "fdc doesn't support drive option rerror");
+ return;
}
}
@@ -2017,7 +2023,6 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
}
}
- return 0;
}
ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
@@ -2047,10 +2052,11 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
{
FDCtrl *fdctrl;
DeviceState *dev;
+ SysBusDevice *sbd;
FDCtrlSysBus *sys;
- dev = qdev_create(NULL, "sysbus-fdc");
- sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
+ dev = qdev_create(NULL, TYPE_SYSBUS_FDC);
+ sys = SYSBUS_FDC(dev);
fdctrl = &sys->state;
fdctrl->dma_chann = dma_chann; /* FIXME */
if (fds[0]) {
@@ -2060,8 +2066,9 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
}
qdev_init_nofail(dev);
- sysbus_connect_irq(&sys->busdev, 0, irq);
- sysbus_mmio_map(&sys->busdev, 0, mmio_base);
+ sbd = SYS_BUS_DEVICE(dev);
+ sysbus_connect_irq(sbd, 0, irq);
+ sysbus_mmio_map(sbd, 0, mmio_base);
}
void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
@@ -2075,13 +2082,13 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
}
qdev_init_nofail(dev);
- sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
- sysbus_connect_irq(&sys->busdev, 0, irq);
- sysbus_mmio_map(&sys->busdev, 0, io_base);
+ sys = SYSBUS_FDC(dev);
+ sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq);
+ sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base);
*fdc_tc = qdev_get_gpio_in(dev, 0);
}
-static int fdctrl_init_common(FDCtrl *fdctrl)
+static void fdctrl_realize_common(FDCtrl *fdctrl, Error **errp)
{
int i, j;
static int command_tables_inited = 0;
@@ -2102,15 +2109,16 @@ static int fdctrl_init_common(FDCtrl *fdctrl)
fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
fdctrl->fifo_size = 512;
fdctrl->result_timer = qemu_new_timer_ns(vm_clock,
- fdctrl_result_timer, fdctrl);
+ fdctrl_result_timer, fdctrl);
fdctrl->version = 0x90; /* Intel 82078 controller */
fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
fdctrl->num_floppies = MAX_FD;
- if (fdctrl->dma_chann != -1)
+ if (fdctrl->dma_chann != -1) {
DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
- return fdctrl_connect_drives(fdctrl);
+ }
+ fdctrl_connect_drives(fdctrl, errp);
}
static const MemoryRegionPortio fdc_portio_list[] = {
@@ -2124,7 +2132,7 @@ static void isabus_fdc_realize(DeviceState *dev, Error **errp)
ISADevice *isadev = ISA_DEVICE(dev);
FDCtrlISABus *isa = ISA_FDC(dev);
FDCtrl *fdctrl = &isa->state;
- int ret;
+ Error *err = NULL;
isa_register_portio_list(isadev, isa->iobase, fdc_portio_list, fdctrl,
"fdc");
@@ -2133,9 +2141,9 @@ static void isabus_fdc_realize(DeviceState *dev, Error **errp)
fdctrl->dma_chann = isa->dma;
qdev_set_legacy_instance_id(dev, isa->iobase, 2);
- ret = fdctrl_init_common(fdctrl);
- if (ret < 0) {
- error_setg(errp, "Floppy init failed.");
+ fdctrl_realize_common(fdctrl, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
return;
}
@@ -2143,38 +2151,62 @@ static void isabus_fdc_realize(DeviceState *dev, Error **errp)
add_boot_device_path(isa->bootindexB, dev, "/floppy@1");
}
-static int sysbus_fdc_init1(SysBusDevice *dev)
+static void sysbus_fdc_initfn(Object *obj)
{
- FDCtrlSysBus *sys = DO_UPCAST(FDCtrlSysBus, busdev, dev);
+ FDCtrlSysBus *sys = SYSBUS_FDC(obj);
FDCtrl *fdctrl = &sys->state;
- int ret;
- memory_region_init_io(&fdctrl->iomem, OBJECT(sys), &fdctrl_mem_ops, fdctrl,
+ memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_ops, fdctrl,
"fdc", 0x08);
- sysbus_init_mmio(dev, &fdctrl->iomem);
- sysbus_init_irq(dev, &fdctrl->irq);
- qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
- fdctrl->dma_chann = -1;
+}
- qdev_set_legacy_instance_id(&dev->qdev, 0 /* io */, 2); /* FIXME */
- ret = fdctrl_init_common(fdctrl);
+static void sysbus_fdc_realize(DeviceState *dev, Error **errp)
+{
+ FDCtrlSysBus *sys = SYSBUS_FDC(dev);
+ FDCtrl *fdctrl = &sys->state;
+ SysBusDevice *b = SYS_BUS_DEVICE(dev);
+ Error *err = NULL;
- return ret;
+ sysbus_init_mmio(b, &fdctrl->iomem);
+ sysbus_init_irq(b, &fdctrl->irq);
+ qdev_init_gpio_in(dev, fdctrl_handle_tc, 1);
+ fdctrl->dma_chann = -1;
+
+ qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */
+ fdctrl_realize_common(fdctrl, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
}
-static int sun4m_fdc_init1(SysBusDevice *dev)
+static void sun4m_fdc_initfn(Object *obj)
{
- FDCtrl *fdctrl = &(FROM_SYSBUS(FDCtrlSysBus, dev)->state);
+ FDCtrlSysBus *sys = SYSBUS_FDC(obj);
+ FDCtrl *fdctrl = &sys->state;
- memory_region_init_io(&fdctrl->iomem, OBJECT(dev), &fdctrl_mem_strict_ops,
+ memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops,
fdctrl, "fdctrl", 0x08);
- sysbus_init_mmio(dev, &fdctrl->iomem);
- sysbus_init_irq(dev, &fdctrl->irq);
- qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
+}
+
+static void sun4m_fdc_realize(DeviceState *dev, Error **errp)
+{
+ FDCtrlSysBus *sys = SYSBUS_FDC(dev);
+ FDCtrl *fdctrl = &sys->state;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ Error *err = NULL;
+
+ sysbus_init_mmio(sbd, &fdctrl->iomem);
+ sysbus_init_irq(sbd, &fdctrl->irq);
+ qdev_init_gpio_in(dev, fdctrl_handle_tc, 1);
fdctrl->sun4m = 1;
- qdev_set_legacy_instance_id(&dev->qdev, 0 /* io */, 2); /* FIXME */
- return fdctrl_init_common(fdctrl);
+ qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */
+ fdctrl_realize_common(fdctrl, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
}
FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
@@ -2245,18 +2277,18 @@ static Property sysbus_fdc_properties[] = {
static void sysbus_fdc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = sysbus_fdc_init1;
+ dc->realize = sysbus_fdc_realize;
dc->reset = fdctrl_external_reset_sysbus;
dc->vmsd = &vmstate_sysbus_fdc;
dc->props = sysbus_fdc_properties;
}
static const TypeInfo sysbus_fdc_info = {
- .name = "sysbus-fdc",
+ .name = TYPE_SYSBUS_FDC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(FDCtrlSysBus),
+ .instance_init = sysbus_fdc_initfn,
.class_init = sysbus_fdc_class_init,
};
@@ -2268,9 +2300,8 @@ static Property sun4m_fdc_properties[] = {
static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = sun4m_fdc_init1;
+ dc->realize = sun4m_fdc_realize;
dc->reset = fdctrl_external_reset_sysbus;
dc->vmsd = &vmstate_sysbus_fdc;
dc->props = sun4m_fdc_properties;
@@ -2280,6 +2311,7 @@ static const TypeInfo sun4m_fdc_info = {
.name = "SUNW,fdtwo",
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(FDCtrlSysBus),
+ .instance_init = sun4m_fdc_initfn,
.class_init = sun4m_fdc_class_init,
};
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index a927a6bc21..8c3b7f0d3b 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -123,10 +123,14 @@ static const FlashPartInfo known_devices[] = {
{ INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) },
/* Micron */
- { INFO("n25q032a", 0x20bb16, 0, 64 << 10, 64, ER_4K) },
- { INFO("n25q128a11", 0x20bb18, 0, 64 << 10, 256, 0) },
- { INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, 0) },
- { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
+ { INFO("n25q032a11", 0x20bb16, 0, 64 << 10, 64, ER_4K) },
+ { INFO("n25q032a13", 0x20ba16, 0, 64 << 10, 64, ER_4K) },
+ { INFO("n25q064a11", 0x20bb17, 0, 64 << 10, 128, ER_4K) },
+ { INFO("n25q064a13", 0x20ba17, 0, 64 << 10, 128, ER_4K) },
+ { INFO("n25q128a11", 0x20bb18, 0, 64 << 10, 256, ER_4K) },
+ { INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, ER_4K) },
+ { INFO("n25q256a11", 0x20bb19, 0, 64 << 10, 512, ER_4K) },
+ { INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
/* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 6898a257d9..2bcd7318bc 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -60,8 +60,14 @@ do { \
#define DPRINTF(fmt, ...) do { } while (0)
#endif
+#define TYPE_CFI_PFLASH01 "cfi.pflash01"
+#define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01)
+
struct pflash_t {
- SysBusDevice busdev;
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
BlockDriverState *bs;
uint32_t nb_blocs;
uint64_t sector_len;
@@ -563,9 +569,9 @@ static const MemoryRegionOps pflash_cfi01_ops_le = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int pflash_cfi01_init(SysBusDevice *dev)
+static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
{
- pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
+ pflash_t *pfl = CFI_PFLASH01(dev);
uint64_t total_len;
int ret;
@@ -584,7 +590,7 @@ static int pflash_cfi01_init(SysBusDevice *dev)
pfl->name, total_len);
vmstate_register_ram(&pfl->mem, DEVICE(pfl));
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
- sysbus_init_mmio(dev, &pfl->mem);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
if (pfl->bs) {
/* read the initial flash content */
@@ -593,7 +599,8 @@ static int pflash_cfi01_init(SysBusDevice *dev)
if (ret < 0) {
vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
memory_region_destroy(&pfl->mem);
- return 1;
+ error_setg(errp, "failed to read the initial flash content");
+ return;
}
}
@@ -690,8 +697,6 @@ static int pflash_cfi01_init(SysBusDevice *dev)
pfl->cfi_table[0x3c] = 0x00;
pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
-
- return 0;
}
static Property pflash_cfi01_properties[] = {
@@ -711,16 +716,15 @@ static Property pflash_cfi01_properties[] = {
static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = pflash_cfi01_init;
+ dc->realize = pflash_cfi01_realize;
dc->props = pflash_cfi01_properties;
dc->vmsd = &vmstate_pflash;
}
static const TypeInfo pflash_cfi01_info = {
- .name = "cfi.pflash01",
+ .name = TYPE_CFI_PFLASH01,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct pflash_t),
.class_init = pflash_cfi01_class_init,
@@ -741,10 +745,7 @@ pflash_t *pflash_cfi01_register(hwaddr base,
uint16_t id0, uint16_t id1,
uint16_t id2, uint16_t id3, int be)
{
- DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
- SysBusDevice *busdev = SYS_BUS_DEVICE(dev);
- pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
- "cfi.pflash01");
+ DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01);
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
abort();
@@ -760,8 +761,8 @@ pflash_t *pflash_cfi01_register(hwaddr base,
qdev_prop_set_string(dev, "name", name);
qdev_init_nofail(dev);
- sysbus_mmio_map(busdev, 0, base);
- return pfl;
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+ return CFI_PFLASH01(dev);
}
MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index d6cd3da46e..9fc02e3d64 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -55,8 +55,14 @@ do { \
#define PFLASH_LAZY_ROMD_THRESHOLD 42
+#define TYPE_CFI_PFLASH02 "cfi.pflash02"
+#define CFI_PFLASH02(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH02)
+
struct pflash_t {
- SysBusDevice busdev;
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
BlockDriverState *bs;
uint32_t sector_len;
uint32_t nb_blocs;
@@ -586,9 +592,9 @@ static const MemoryRegionOps pflash_cfi02_ops_le = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int pflash_cfi02_init(SysBusDevice *dev)
+static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
{
- pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
+ pflash_t *pfl = CFI_PFLASH02(dev);
uint32_t chip_len;
int ret;
@@ -610,14 +616,16 @@ static int pflash_cfi02_init(SysBusDevice *dev)
/* read the initial flash content */
ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
if (ret < 0) {
- g_free(pfl);
- return 1;
+ vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
+ memory_region_destroy(&pfl->orig_mem);
+ error_setg(errp, "failed to read the initial flash content");
+ return;
}
}
pflash_setup_mappings(pfl);
pfl->rom_mode = 1;
- sysbus_init_mmio(dev, &pfl->mem);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
if (pfl->bs) {
pfl->ro = bdrv_is_read_only(pfl->bs);
@@ -706,8 +714,6 @@ static int pflash_cfi02_init(SysBusDevice *dev)
pfl->cfi_table[0x3b] = 0x00;
pfl->cfi_table[0x3c] = 0x00;
-
- return 0;
}
static Property pflash_cfi02_properties[] = {
@@ -730,14 +736,13 @@ static Property pflash_cfi02_properties[] = {
static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = pflash_cfi02_init;
+ dc->realize = pflash_cfi02_realize;
dc->props = pflash_cfi02_properties;
}
static const TypeInfo pflash_cfi02_info = {
- .name = "cfi.pflash02",
+ .name = TYPE_CFI_PFLASH02,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct pflash_t),
.class_init = pflash_cfi02_class_init,
@@ -760,10 +765,7 @@ pflash_t *pflash_cfi02_register(hwaddr base,
uint16_t unlock_addr0, uint16_t unlock_addr1,
int be)
{
- DeviceState *dev = qdev_create(NULL, "cfi.pflash02");
- SysBusDevice *busdev = SYS_BUS_DEVICE(dev);
- pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
- "cfi.pflash02");
+ DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH02);
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
abort();
@@ -782,6 +784,6 @@ pflash_t *pflash_cfi02_register(hwaddr base,
qdev_prop_set_string(dev, "name", name);
qdev_init_nofail(dev);
- sysbus_mmio_map(busdev, 0, base);
- return pfl;
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+ return CFI_PFLASH02(dev);
}
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 44311ff43d..c3c28cf6af 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -434,15 +434,17 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
}
/* Load a U-Boot image. */
-int load_uimage(const char *filename, hwaddr *ep,
- hwaddr *loadaddr, int *is_linux)
+static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
+ int *is_linux, uint8_t image_type)
{
int fd;
int size;
+ hwaddr address;
uboot_image_header_t h;
uboot_image_header_t *hdr = &h;
uint8_t *data = NULL;
int ret = -1;
+ int do_uncompress = 0;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
@@ -457,32 +459,55 @@ int load_uimage(const char *filename, hwaddr *ep,
if (hdr->ih_magic != IH_MAGIC)
goto out;
- /* TODO: Implement other image types. */
- if (hdr->ih_type != IH_TYPE_KERNEL) {
- fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
+ if (hdr->ih_type != image_type) {
+ fprintf(stderr, "Wrong image type %d, expected %d\n", hdr->ih_type,
+ image_type);
goto out;
}
- switch (hdr->ih_comp) {
- case IH_COMP_NONE:
- case IH_COMP_GZIP:
+ /* TODO: Implement other image types. */
+ switch (hdr->ih_type) {
+ case IH_TYPE_KERNEL:
+ address = hdr->ih_load;
+ if (loadaddr) {
+ *loadaddr = hdr->ih_load;
+ }
+
+ switch (hdr->ih_comp) {
+ case IH_COMP_NONE:
+ break;
+ case IH_COMP_GZIP:
+ do_uncompress = 1;
+ break;
+ default:
+ fprintf(stderr,
+ "Unable to load u-boot images with compression type %d\n",
+ hdr->ih_comp);
+ goto out;
+ }
+
+ if (ep) {
+ *ep = hdr->ih_ep;
+ }
+
+ /* TODO: Check CPU type. */
+ if (is_linux) {
+ if (hdr->ih_os == IH_OS_LINUX) {
+ *is_linux = 1;
+ } else {
+ *is_linux = 0;
+ }
+ }
+
+ break;
+ case IH_TYPE_RAMDISK:
+ address = *loadaddr;
break;
default:
- fprintf(stderr,
- "Unable to load u-boot images with compression type %d\n",
- hdr->ih_comp);
+ fprintf(stderr, "Unsupported u-boot image type %d\n", hdr->ih_type);
goto out;
}
- /* TODO: Check CPU type. */
- if (is_linux) {
- if (hdr->ih_os == IH_OS_LINUX)
- *is_linux = 1;
- else
- *is_linux = 0;
- }
-
- *ep = hdr->ih_ep;
data = g_malloc(hdr->ih_size);
if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
@@ -490,7 +515,7 @@ int load_uimage(const char *filename, hwaddr *ep,
goto out;
}
- if (hdr->ih_comp == IH_COMP_GZIP) {
+ if (do_uncompress) {
uint8_t *compressed_data;
size_t max_bytes;
ssize_t bytes;
@@ -508,10 +533,7 @@ int load_uimage(const char *filename, hwaddr *ep,
hdr->ih_size = bytes;
}
- rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);
-
- if (loadaddr)
- *loadaddr = hdr->ih_load;
+ rom_add_blob_fixed(filename, data, hdr->ih_size, address);
ret = hdr->ih_size;
@@ -522,6 +544,18 @@ out:
return ret;
}
+int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
+ int *is_linux)
+{
+ return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL);
+}
+
+/* Load a ramdisk. */
+int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
+{
+ return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK);
+}
+
/*
* Functions for reboot-persistent memory regions.
* - used for vga bios and option roms.
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 714908f44c..3536cded92 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -81,8 +81,16 @@ struct vmsvga_state_s {
int redraw_fifo_first, redraw_fifo_last;
};
+#define TYPE_VMWARE_SVGA "vmware-svga"
+
+#define VMWARE_SVGA(obj) \
+ OBJECT_CHECK(struct pci_vmsvga_state_s, (obj), TYPE_VMWARE_SVGA)
+
struct pci_vmsvga_state_s {
- PCIDevice card;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
struct vmsvga_state_s chip;
MemoryRegion io_bar;
};
@@ -787,7 +795,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
case SVGA_REG_FB_START: {
struct pci_vmsvga_state_s *pci_vmsvga
= container_of(s, struct pci_vmsvga_state_s, chip);
- ret = pci_get_bar_addr(&pci_vmsvga->card, 1);
+ ret = pci_get_bar_addr(PCI_DEVICE(pci_vmsvga), 1);
break;
}
@@ -823,7 +831,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
case SVGA_REG_MEM_START: {
struct pci_vmsvga_state_s *pci_vmsvga
= container_of(s, struct pci_vmsvga_state_s, chip);
- ret = pci_get_bar_addr(&pci_vmsvga->card, 2);
+ ret = pci_get_bar_addr(PCI_DEVICE(pci_vmsvga), 2);
break;
}
@@ -1092,8 +1100,7 @@ static void vmsvga_update_display(void *opaque)
static void vmsvga_reset(DeviceState *dev)
{
- struct pci_vmsvga_state_s *pci =
- DO_UPCAST(struct pci_vmsvga_state_s, card.qdev, dev);
+ struct pci_vmsvga_state_s *pci = VMWARE_SVGA(dev);
struct vmsvga_state_s *s = &pci->chip;
s->index = 0;
@@ -1172,7 +1179,7 @@ static const VMStateDescription vmstate_vmware_vga = {
.minimum_version_id = 0,
.minimum_version_id_old = 0,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(card, struct pci_vmsvga_state_s),
+ VMSTATE_PCI_DEVICE(parent_obj, struct pci_vmsvga_state_s),
VMSTATE_STRUCT(chip, struct pci_vmsvga_state_s, 0,
vmstate_vmware_vga_internal, struct vmsvga_state_s),
VMSTATE_END_OF_LIST()
@@ -1250,24 +1257,23 @@ static const MemoryRegionOps vmsvga_io_ops = {
static int pci_vmsvga_initfn(PCIDevice *dev)
{
- struct pci_vmsvga_state_s *s =
- DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
+ struct pci_vmsvga_state_s *s = VMWARE_SVGA(dev);
- s->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */
- s->card.config[PCI_LATENCY_TIMER] = 0x40; /* Latency timer */
- s->card.config[PCI_INTERRUPT_LINE] = 0xff; /* End */
+ dev->config[PCI_CACHE_LINE_SIZE] = 0x08;
+ dev->config[PCI_LATENCY_TIMER] = 0x40;
+ dev->config[PCI_INTERRUPT_LINE] = 0xff; /* End */
memory_region_init_io(&s->io_bar, NULL, &vmsvga_io_ops, &s->chip,
"vmsvga-io", 0x10);
memory_region_set_flush_coalesced(&s->io_bar);
- pci_register_bar(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
vmsvga_init(DEVICE(dev), &s->chip,
pci_address_space(dev), pci_address_space_io(dev));
- pci_register_bar(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
&s->chip.vga.vram);
- pci_register_bar(&s->card, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
+ pci_register_bar(dev, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
&s->chip.fifo_ram);
if (!dev->rom_bar) {
@@ -1303,7 +1309,7 @@ static void vmsvga_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo vmsvga_info = {
- .name = "vmware-svga",
+ .name = TYPE_VMWARE_SVGA,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(struct pci_vmsvga_state_s),
.class_init = vmsvga_class_init,
diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c
index 52bffa5010..42f5e89496 100644
--- a/hw/i2c/exynos4210_i2c.c
+++ b/hw/i2c/exynos4210_i2c.c
@@ -271,7 +271,7 @@ static const MemoryRegionOps exynos4210_i2c_ops = {
};
static const VMStateDescription exynos4210_i2c_vmstate = {
- .name = TYPE_EXYNOS4_I2C,
+ .name = "exynos4210.i2c",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
index 1022d67178..e89e2f768e 100644
--- a/hw/i386/kvm/clock.c
+++ b/hw/i386/kvm/clock.c
@@ -22,8 +22,14 @@
#include <linux/kvm.h>
#include <linux/kvm_para.h>
+#define TYPE_KVM_CLOCK "kvmclock"
+#define KVM_CLOCK(obj) OBJECT_CHECK(KVMClockState, (obj), TYPE_KVM_CLOCK)
+
typedef struct KVMClockState {
+ /*< private >*/
SysBusDevice busdev;
+ /*< public >*/
+
uint64_t clock;
bool clock_valid;
} KVMClockState;
@@ -85,12 +91,11 @@ static void kvmclock_vm_state_change(void *opaque, int running,
}
}
-static int kvmclock_init(SysBusDevice *dev)
+static void kvmclock_realize(DeviceState *dev, Error **errp)
{
- KVMClockState *s = FROM_SYSBUS(KVMClockState, dev);
+ KVMClockState *s = KVM_CLOCK(dev);
qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
- return 0;
}
static const VMStateDescription kvmclock_vmsd = {
@@ -107,15 +112,14 @@ static const VMStateDescription kvmclock_vmsd = {
static void kvmclock_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = kvmclock_init;
+ dc->realize = kvmclock_realize;
dc->no_user = 1;
dc->vmsd = &kvmclock_vmsd;
}
static const TypeInfo kvmclock_info = {
- .name = "kvmclock",
+ .name = TYPE_KVM_CLOCK,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(KVMClockState),
.class_init = kvmclock_class_init,
@@ -129,7 +133,7 @@ void kvmclock_create(void)
if (kvm_enabled() &&
cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
(1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
- sysbus_create_simple("kvmclock", -1, NULL);
+ sysbus_create_simple(TYPE_KVM_CLOCK, -1, NULL);
}
}
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index ccd089a40e..a4506bcf42 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -146,6 +146,7 @@ static void update_guest_rom_state(VAPICROMState *s)
static int find_real_tpr_addr(VAPICROMState *s, CPUX86State *env)
{
+ CPUState *cs = CPU(x86_env_get_cpu(env));
hwaddr paddr;
target_ulong addr;
@@ -158,7 +159,7 @@ static int find_real_tpr_addr(VAPICROMState *s, CPUX86State *env)
* virtual address space for the APIC mapping.
*/
for (addr = 0xfffff000; addr >= 0x80000000; addr -= TARGET_PAGE_SIZE) {
- paddr = cpu_get_phys_page_debug(env, addr);
+ paddr = cpu_get_phys_page_debug(cs, addr);
if (paddr != APIC_DEFAULT_ADDRESS) {
continue;
}
@@ -187,9 +188,10 @@ static bool opcode_matches(uint8_t *opcode, const TPRInstruction *instr)
modrm_reg(opcode[1]) == instr->modrm_reg);
}
-static int evaluate_tpr_instruction(VAPICROMState *s, CPUX86State *env,
+static int evaluate_tpr_instruction(VAPICROMState *s, X86CPU *cpu,
target_ulong *pip, TPRAccess access)
{
+ CPUState *cs = CPU(cpu);
const TPRInstruction *instr;
target_ulong ip = *pip;
uint8_t opcode[2];
@@ -210,7 +212,7 @@ static int evaluate_tpr_instruction(VAPICROMState *s, CPUX86State *env,
* RSP, used by the patched instruction, is zero, so the guest gets a
* double fault and dies.
*/
- if (env->regs[R_ESP] == 0) {
+ if (cpu->env.regs[R_ESP] == 0) {
return -1;
}
@@ -225,7 +227,7 @@ static int evaluate_tpr_instruction(VAPICROMState *s, CPUX86State *env,
if (instr->access != access) {
continue;
}
- if (cpu_memory_rw_debug(env, ip - instr->length, opcode,
+ if (cpu_memory_rw_debug(cs, ip - instr->length, opcode,
sizeof(opcode), 0) < 0) {
return -1;
}
@@ -236,7 +238,7 @@ static int evaluate_tpr_instruction(VAPICROMState *s, CPUX86State *env,
}
return -1;
} else {
- if (cpu_memory_rw_debug(env, ip, opcode, sizeof(opcode), 0) < 0) {
+ if (cpu_memory_rw_debug(cs, ip, opcode, sizeof(opcode), 0) < 0) {
return -1;
}
for (i = 0; i < ARRAY_SIZE(tpr_instr); i++) {
@@ -253,7 +255,7 @@ instruction_ok:
* Grab the virtual TPR address from the instruction
* and update the cached values.
*/
- if (cpu_memory_rw_debug(env, ip + instr->addr_offset,
+ if (cpu_memory_rw_debug(cs, ip + instr->addr_offset,
(void *)&real_tpr_addr,
sizeof(real_tpr_addr), 0) < 0) {
return -1;
@@ -271,6 +273,7 @@ instruction_ok:
static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong ip)
{
+ CPUState *cs = CPU(x86_env_get_cpu(env));
hwaddr paddr;
uint32_t rom_state_vaddr;
uint32_t pos, patch, offset;
@@ -287,7 +290,7 @@ static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong i
/* find out virtual address of the ROM */
rom_state_vaddr = s->rom_state_paddr + (ip & 0xf0000000);
- paddr = cpu_get_phys_page_debug(env, rom_state_vaddr);
+ paddr = cpu_get_phys_page_debug(cs, rom_state_vaddr);
if (paddr == -1) {
return -1;
}
@@ -332,8 +335,9 @@ static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong i
* cannot be accessed or is considered invalid. This also ensures that we are
* not patching the wrong guest.
*/
-static int get_kpcr_number(CPUX86State *env)
+static int get_kpcr_number(X86CPU *cpu)
{
+ CPUX86State *env = &cpu->env;
struct kpcr {
uint8_t fill1[0x1c];
uint32_t self;
@@ -341,7 +345,7 @@ static int get_kpcr_number(CPUX86State *env)
uint8_t number;
} QEMU_PACKED kpcr;
- if (cpu_memory_rw_debug(env, env->segs[R_FS].base,
+ if (cpu_memory_rw_debug(CPU(cpu), env->segs[R_FS].base,
(void *)&kpcr, sizeof(kpcr), 0) < 0 ||
kpcr.self != env->segs[R_FS].base) {
return -1;
@@ -349,9 +353,9 @@ static int get_kpcr_number(CPUX86State *env)
return kpcr.number;
}
-static int vapic_enable(VAPICROMState *s, CPUX86State *env)
+static int vapic_enable(VAPICROMState *s, X86CPU *cpu)
{
- int cpu_number = get_kpcr_number(env);
+ int cpu_number = get_kpcr_number(cpu);
hwaddr vapic_paddr;
static const uint8_t enabled = 1;
@@ -362,26 +366,26 @@ static int vapic_enable(VAPICROMState *s, CPUX86State *env)
(((hwaddr)cpu_number) << VAPIC_CPU_SHIFT);
cpu_physical_memory_rw(vapic_paddr + offsetof(VAPICState, enabled),
(void *)&enabled, sizeof(enabled), 1);
- apic_enable_vapic(env->apic_state, vapic_paddr);
+ apic_enable_vapic(cpu->env.apic_state, vapic_paddr);
s->state = VAPIC_ACTIVE;
return 0;
}
-static void patch_byte(CPUX86State *env, target_ulong addr, uint8_t byte)
+static void patch_byte(X86CPU *cpu, target_ulong addr, uint8_t byte)
{
- cpu_memory_rw_debug(env, addr, &byte, 1, 1);
+ cpu_memory_rw_debug(CPU(cpu), addr, &byte, 1, 1);
}
-static void patch_call(VAPICROMState *s, CPUX86State *env, target_ulong ip,
+static void patch_call(VAPICROMState *s, X86CPU *cpu, target_ulong ip,
uint32_t target)
{
uint32_t offset;
offset = cpu_to_le32(target - ip - 5);
- patch_byte(env, ip, 0xe8); /* call near */
- cpu_memory_rw_debug(env, ip + 1, (void *)&offset, sizeof(offset), 1);
+ patch_byte(cpu, ip, 0xe8); /* call near */
+ cpu_memory_rw_debug(CPU(cpu), ip + 1, (void *)&offset, sizeof(offset), 1);
}
static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
@@ -409,32 +413,32 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
pause_all_vcpus();
- cpu_memory_rw_debug(env, ip, opcode, sizeof(opcode), 0);
+ cpu_memory_rw_debug(cs, ip, opcode, sizeof(opcode), 0);
switch (opcode[0]) {
case 0x89: /* mov r32 to r/m32 */
- patch_byte(env, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */
- patch_call(s, env, ip + 1, handlers->set_tpr);
+ patch_byte(cpu, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */
+ patch_call(s, cpu, ip + 1, handlers->set_tpr);
break;
case 0x8b: /* mov r/m32 to r32 */
- patch_byte(env, ip, 0x90);
- patch_call(s, env, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]);
+ patch_byte(cpu, ip, 0x90);
+ patch_call(s, cpu, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]);
break;
case 0xa1: /* mov abs to eax */
- patch_call(s, env, ip, handlers->get_tpr[0]);
+ patch_call(s, cpu, ip, handlers->get_tpr[0]);
break;
case 0xa3: /* mov eax to abs */
- patch_call(s, env, ip, handlers->set_tpr_eax);
+ patch_call(s, cpu, ip, handlers->set_tpr_eax);
break;
case 0xc7: /* mov imm32, r/m32 (c7/0) */
- patch_byte(env, ip, 0x68); /* push imm32 */
- cpu_memory_rw_debug(env, ip + 6, (void *)&imm32, sizeof(imm32), 0);
- cpu_memory_rw_debug(env, ip + 1, (void *)&imm32, sizeof(imm32), 1);
- patch_call(s, env, ip + 5, handlers->set_tpr);
+ patch_byte(cpu, ip, 0x68); /* push imm32 */
+ cpu_memory_rw_debug(cs, ip + 6, (void *)&imm32, sizeof(imm32), 0);
+ cpu_memory_rw_debug(cs, ip + 1, (void *)&imm32, sizeof(imm32), 1);
+ patch_call(s, cpu, ip + 5, handlers->set_tpr);
break;
case 0xff: /* push r/m32 */
- patch_byte(env, ip, 0x50); /* push eax */
- patch_call(s, env, ip + 1, handlers->get_tpr_stack);
+ patch_byte(cpu, ip, 0x50); /* push eax */
+ patch_call(s, cpu, ip + 1, handlers->get_tpr_stack);
break;
default:
abort();
@@ -458,16 +462,16 @@ void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip,
cpu_synchronize_state(cs);
- if (evaluate_tpr_instruction(s, env, &ip, access) < 0) {
+ if (evaluate_tpr_instruction(s, cpu, &ip, access) < 0) {
if (s->state == VAPIC_ACTIVE) {
- vapic_enable(s, env);
+ vapic_enable(s, cpu);
}
return;
}
if (update_rom_mapping(s, env, ip) < 0) {
return;
}
- if (vapic_enable(s, env) < 0) {
+ if (vapic_enable(s, cpu) < 0) {
return;
}
patch_instruction(s, cpu, ip);
@@ -667,8 +671,8 @@ static void vapic_write(void *opaque, hwaddr addr, uint64_t data,
* accurate.
*/
pause_all_vcpus();
- patch_byte(env, env->eip - 2, 0x66);
- patch_byte(env, env->eip - 1, 0x90);
+ patch_byte(cpu, env->eip - 2, 0x66);
+ patch_byte(cpu, env->eip - 1, 0x90);
resume_all_vcpus();
}
@@ -681,7 +685,7 @@ static void vapic_write(void *opaque, hwaddr addr, uint64_t data,
if (find_real_tpr_addr(s, env) < 0) {
break;
}
- vapic_enable(s, env);
+ vapic_enable(s, cpu);
break;
default:
case 4:
@@ -703,19 +707,18 @@ static const MemoryRegionOps vapic_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int vapic_init(SysBusDevice *dev)
+static void vapic_realize(DeviceState *dev, Error **errp)
{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
VAPICROMState *s = VAPIC(dev);
memory_region_init_io(&s->io, OBJECT(s), &vapic_ops, s, "kvmvapic", 2);
- sysbus_add_io(dev, VAPIC_IO_PORT, &s->io);
- sysbus_init_ioports(dev, VAPIC_IO_PORT, 2);
+ sysbus_add_io(sbd, VAPIC_IO_PORT, &s->io);
+ sysbus_init_ioports(sbd, VAPIC_IO_PORT, 2);
option_rom[nb_option_roms].name = "kvmvapic.bin";
option_rom[nb_option_roms].bootindex = -1;
nb_option_roms++;
-
- return 0;
}
static void do_vapic_enable(void *data)
@@ -723,7 +726,7 @@ static void do_vapic_enable(void *data)
VAPICROMState *s = data;
X86CPU *cpu = X86_CPU(first_cpu);
- vapic_enable(s, &cpu->env);
+ vapic_enable(s, cpu);
}
static int vapic_post_load(void *opaque, int version_id)
@@ -812,13 +815,12 @@ static const VMStateDescription vmstate_vapic = {
static void vapic_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->no_user = 1;
dc->reset = vapic_reset;
dc->vmsd = &vmstate_vapic;
- sc->init = vapic_init;
+ dc->realize = vapic_realize;
}
static const TypeInfo vapic_type = {
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index c5d8570af1..2a8756321b 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1005,7 +1005,7 @@ typedef struct PcRomPciInfo {
static void pc_fw_cfg_guest_info(PcGuestInfo *guest_info)
{
PcRomPciInfo *info;
- if (!guest_info->has_pci_info) {
+ if (!guest_info->has_pci_info || !guest_info->fw_cfg) {
return;
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 6f10246edf..0b1d2e32f7 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -60,6 +60,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
const char *boot_device = args->boot_device;
ram_addr_t below_4g_mem_size, above_4g_mem_size;
Q35PCIHost *q35_host;
+ PCIHostState *phb;
PCIBus *host_bus;
PCIDevice *lpc;
BusState *idebus[MAX_SATA_PORTS];
@@ -139,7 +140,8 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
q35_host->mch.guest_info = guest_info;
/* pci */
qdev_init_nofail(DEVICE(q35_host));
- host_bus = q35_host->host.pci.bus;
+ phb = PCI_HOST_BRIDGE(q35_host);
+ host_bus = phb->bus;
/* create ISA bus */
lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
ICH9_LPC_FUNC), true,
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 1d863b5784..419adde0ea 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -117,12 +117,13 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
{
- struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
+ AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
+ PCIDevice *pci_dev = PCI_DEVICE(d);
DPRINTF(0, "raise irq\n");
- if (msi_enabled(&d->card)) {
- msi_notify(&d->card, 0);
+ if (msi_enabled(pci_dev)) {
+ msi_notify(pci_dev, 0);
} else {
qemu_irq_raise(s->irq);
}
@@ -130,11 +131,11 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
{
- struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
+ AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
DPRINTF(0, "lower irq\n");
- if (!msi_enabled(&d->card)) {
+ if (!msi_enabled(PCI_DEVICE(d))) {
qemu_irq_lower(s->irq);
}
}
@@ -1285,8 +1286,14 @@ const VMStateDescription vmstate_ahci = {
},
};
+#define TYPE_SYSBUS_AHCI "sysbus-ahci"
+#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI)
+
typedef struct SysbusAHCIState {
- SysBusDevice busdev;
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
AHCIState ahci;
uint32_t num_ports;
} SysbusAHCIState;
@@ -1302,19 +1309,20 @@ static const VMStateDescription vmstate_sysbus_ahci = {
static void sysbus_ahci_reset(DeviceState *dev)
{
- SysbusAHCIState *s = DO_UPCAST(SysbusAHCIState, busdev.qdev, dev);
+ SysbusAHCIState *s = SYSBUS_AHCI(dev);
ahci_reset(&s->ahci);
}
-static int sysbus_ahci_init(SysBusDevice *dev)
+static void sysbus_ahci_realize(DeviceState *dev, Error **errp)
{
- SysbusAHCIState *s = FROM_SYSBUS(SysbusAHCIState, dev);
- ahci_init(&s->ahci, &dev->qdev, NULL, s->num_ports);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ SysbusAHCIState *s = SYSBUS_AHCI(dev);
- sysbus_init_mmio(dev, &s->ahci.mem);
- sysbus_init_irq(dev, &s->ahci.irq);
- return 0;
+ ahci_init(&s->ahci, dev, NULL, s->num_ports);
+
+ sysbus_init_mmio(sbd, &s->ahci.mem);
+ sysbus_init_irq(sbd, &s->ahci.irq);
}
static Property sysbus_ahci_properties[] = {
@@ -1324,17 +1332,16 @@ static Property sysbus_ahci_properties[] = {
static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- sbc->init = sysbus_ahci_init;
+ dc->realize = sysbus_ahci_realize;
dc->vmsd = &vmstate_sysbus_ahci;
dc->props = sysbus_ahci_properties;
dc->reset = sysbus_ahci_reset;
}
static const TypeInfo sysbus_ahci_info = {
- .name = "sysbus-ahci",
+ .name = TYPE_SYSBUS_AHCI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SysbusAHCIState),
.class_init = sysbus_ahci_class_init,
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 341a5711ee..20e412c240 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -301,10 +301,18 @@ typedef struct AHCIState {
} AHCIState;
typedef struct AHCIPCIState {
- PCIDevice card;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
AHCIState ahci;
} AHCIPCIState;
+#define TYPE_ICH9_AHCI "ich9-ahci"
+
+#define ICH_AHCI(obj) \
+ OBJECT_CHECK(AHCIPCIState, (obj), TYPE_ICH9_AHCI)
+
extern const VMStateDescription vmstate_ahci;
#define VMSTATE_AHCI(_field, _state) { \
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 6c0c0c2935..4eb5488993 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -84,7 +84,7 @@ static const VMStateDescription vmstate_ich9_ahci = {
.unmigratable = 1, /* Still buggy under I/O load */
.version_id = 1,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(card, AHCIPCIState),
+ VMSTATE_PCI_DEVICE(parent_obj, AHCIPCIState),
VMSTATE_AHCI(ahci, AHCIPCIState),
VMSTATE_END_OF_LIST()
},
@@ -92,7 +92,7 @@ static const VMStateDescription vmstate_ich9_ahci = {
static void pci_ich9_reset(DeviceState *dev)
{
- struct AHCIPCIState *d = DO_UPCAST(struct AHCIPCIState, card.qdev, dev);
+ AHCIPCIState *d = ICH_AHCI(dev);
ahci_reset(&d->ahci);
}
@@ -102,34 +102,34 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
struct AHCIPCIState *d;
int sata_cap_offset;
uint8_t *sata_cap;
- d = DO_UPCAST(struct AHCIPCIState, card, dev);
+ d = ICH_AHCI(dev);
- ahci_init(&d->ahci, &dev->qdev, pci_get_address_space(dev), 6);
+ ahci_init(&d->ahci, DEVICE(dev), pci_get_address_space(dev), 6);
- pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
+ pci_config_set_prog_interface(dev->config, AHCI_PROGMODE_MAJOR_REV_1);
- d->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */
- d->card.config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */
- pci_config_set_interrupt_pin(d->card.config, 1);
+ dev->config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */
+ dev->config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */
+ pci_config_set_interrupt_pin(dev->config, 1);
/* XXX Software should program this register */
- d->card.config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
+ dev->config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
msi_init(dev, 0x50, 1, true, false);
- d->ahci.irq = d->card.irq[0];
+ d->ahci.irq = dev->irq[0];
- pci_register_bar(&d->card, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO,
+ pci_register_bar(dev, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO,
&d->ahci.idp);
- pci_register_bar(&d->card, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ pci_register_bar(dev, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY,
&d->ahci.mem);
- sata_cap_offset = pci_add_capability(&d->card, PCI_CAP_ID_SATA,
+ sata_cap_offset = pci_add_capability(dev, PCI_CAP_ID_SATA,
ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE);
if (sata_cap_offset < 0) {
return sata_cap_offset;
}
- sata_cap = d->card.config + sata_cap_offset;
+ sata_cap = dev->config + sata_cap_offset;
pci_set_word(sata_cap + SATA_CAP_REV, 0x10);
pci_set_long(sata_cap + SATA_CAP_BAR,
(ICH9_IDP_BAR + 0x4) | (ICH9_IDP_INDEX_LOG2 << 4));
@@ -141,7 +141,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
static void pci_ich9_uninit(PCIDevice *dev)
{
struct AHCIPCIState *d;
- d = DO_UPCAST(struct AHCIPCIState, card, dev);
+ d = ICH_AHCI(dev);
msi_uninit(dev);
ahci_uninit(&d->ahci);
@@ -163,7 +163,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ich_ahci_info = {
- .name = "ich9-ahci",
+ .name = TYPE_ICH9_AHCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(AHCIPCIState),
.class_init = ich_ahci_class_init,
diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c
index 5c5bb3caaa..6b705c1546 100644
--- a/hw/intc/ioapic_common.c
+++ b/hw/intc/ioapic_common.c
@@ -57,23 +57,22 @@ static int ioapic_dispatch_post_load(void *opaque, int version_id)
return 0;
}
-static int ioapic_init_common(SysBusDevice *dev)
+static void ioapic_common_realize(DeviceState *dev, Error **errp)
{
IOAPICCommonState *s = IOAPIC_COMMON(dev);
IOAPICCommonClass *info;
static int ioapic_no;
if (ioapic_no >= MAX_IOAPICS) {
- return -1;
+ error_setg(errp, "Only %d ioapics allowed", MAX_IOAPICS);
+ return;
}
info = IOAPIC_COMMON_GET_CLASS(s);
info->init(s, ioapic_no);
- sysbus_init_mmio(&s->busdev, &s->io_memory);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->io_memory);
ioapic_no++;
-
- return 0;
}
static const VMStateDescription vmstate_ioapic_common = {
@@ -95,10 +94,9 @@ static const VMStateDescription vmstate_ioapic_common = {
static void ioapic_common_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- sc->init = ioapic_init_common;
+ dc->realize = ioapic_common_realize;
dc->vmsd = &vmstate_ioapic_common;
dc->no_user = 1;
}
diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs
index 193746a73e..9164556a4d 100644
--- a/hw/isa/Makefile.objs
+++ b/hw/isa/Makefile.objs
@@ -1,7 +1,6 @@
common-obj-y += isa-bus.o
common-obj-$(CONFIG_APM) += apm.o
common-obj-$(CONFIG_I82378) += i82378.o
-common-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
common-obj-$(CONFIG_PC87312) += pc87312.o
common-obj-$(CONFIG_PIIX4) += piix4.o
common-obj-$(CONFIG_VT82C686) += vt82c686.o
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index cfd610c681..9e104eb9a7 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -192,18 +192,10 @@ static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
}
}
-static int isabus_bridge_init(SysBusDevice *dev)
-{
- /* nothing */
- return 0;
-}
-
static void isabus_bridge_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = isabus_bridge_init;
dc->fw_name = "isa";
dc->no_user = 1;
}
diff --git a/hw/isa/isa_mmio.c b/hw/isa/isa_mmio.c
deleted file mode 100644
index 00ae8ebc2e..0000000000
--- a/hw/isa/isa_mmio.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Memory mapped access to ISA IO space.
- *
- * 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 "hw/hw.h"
-#include "hw/isa/isa.h"
-#include "exec/address-spaces.h"
-
-static void isa_mmio_writeb (void *opaque, hwaddr addr,
- uint32_t val)
-{
- cpu_outb(addr & IOPORTS_MASK, val);
-}
-
-static void isa_mmio_writew(void *opaque, hwaddr addr,
- uint32_t val)
-{
- cpu_outw(addr & IOPORTS_MASK, val);
-}
-
-static void isa_mmio_writel(void *opaque, hwaddr addr,
- uint32_t val)
-{
- cpu_outl(addr & IOPORTS_MASK, val);
-}
-
-static uint32_t isa_mmio_readb (void *opaque, hwaddr addr)
-{
- return cpu_inb(addr & IOPORTS_MASK);
-}
-
-static uint32_t isa_mmio_readw(void *opaque, hwaddr addr)
-{
- return cpu_inw(addr & IOPORTS_MASK);
-}
-
-static uint32_t isa_mmio_readl(void *opaque, hwaddr addr)
-{
- return cpu_inl(addr & IOPORTS_MASK);
-}
-
-static const MemoryRegionOps isa_mmio_ops = {
- .old_mmio = {
- .write = { isa_mmio_writeb, isa_mmio_writew, isa_mmio_writel },
- .read = { isa_mmio_readb, isa_mmio_readw, isa_mmio_readl, },
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void isa_mmio_setup(MemoryRegion *mr, hwaddr size)
-{
- memory_region_init_io(mr, NULL, &isa_mmio_ops, NULL, "isa-mmio", size);
-}
-
-void isa_mmio_init(hwaddr base, hwaddr size)
-{
- MemoryRegion *mr = g_malloc(sizeof(*mr));
-
- isa_mmio_setup(mr, size);
- memory_region_add_subregion(get_system_memory(), base, mr);
-}
diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c
index 5843417567..3da2e67098 100644
--- a/hw/mips/gt64xxx_pci.c
+++ b/hw/mips/gt64xxx_pci.c
@@ -304,7 +304,8 @@ static void gt64120_pci_mapping(GT64120State *s)
s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
isa_mem_base = s->PCI0IO_start;
if (s->PCI0IO_length) {
- isa_mmio_setup(&s->PCI0IO_mem, s->PCI0IO_length);
+ memory_region_init_alias(&s->PCI0IO_mem, OBJECT(s), "isa_mmio",
+ get_system_io(), 0, s->PCI0IO_length);
memory_region_add_subregion(get_system_memory(), s->PCI0IO_start,
&s->PCI0IO_mem);
}
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index 9e305d2878..a7e9dcf4bf 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -333,8 +333,7 @@ static void mips_fulong2e_init(QEMUMachineInitArgs *args)
}
if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
- fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n", bios_name);
- exit(1);
+ fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", bios_name);
}
}
diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c
index 31e138b056..d6e0860a83 100644
--- a/hw/mips/mips_jazz.c
+++ b/hw/mips/mips_jazz.c
@@ -119,6 +119,7 @@ static void mips_jazz_init(MemoryRegion *address_space,
qemu_irq *rc4030, *i8259;
rc4030_dma *dmas;
void* rc4030_opaque;
+ MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *rtc = g_new(MemoryRegion, 1);
MemoryRegion *i8042 = g_new(MemoryRegion, 1);
MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
@@ -176,9 +177,8 @@ static void mips_jazz_init(MemoryRegion *address_space,
bios_size = -1;
}
if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) {
- fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n",
+ fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
bios_name);
- exit(1);
}
/* Init CPU internal devices */
@@ -201,7 +201,9 @@ static void mips_jazz_init(MemoryRegion *address_space,
pcspk_init(isa_bus, pit);
/* ISA IO space at 0x90000000 */
- isa_mmio_init(0x90000000, 0x01000000);
+ memory_region_init_alias(isa, NULL, "isa_mmio",
+ get_system_io(), 0, 0x01000000);
+ memory_region_add_subregion(address_space, 0x90000000, isa);
isa_mem_base = 0x11000000;
/* Video card */
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index de87241e9c..dad58c0ed2 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -908,9 +908,8 @@ void mips_malta_init(QEMUMachineInitArgs *args)
}
if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
fprintf(stderr,
- "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
+ "qemu: Warning, could not load MIPS bios '%s', and no -kernel argument was specified\n",
bios_name);
- exit(1);
}
}
/* In little endian mode the 32bit words in the bios are swapped,
diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c
index a10cf13a92..e8802c128e 100644
--- a/hw/mips/mips_mipssim.c
+++ b/hw/mips/mips_mipssim.c
@@ -140,6 +140,7 @@ mips_mipssim_init(QEMUMachineInitArgs *args)
const char *initrd_filename = args->initrd_filename;
char *filename;
MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *ram = g_new(MemoryRegion, 1);
MemoryRegion *bios = g_new(MemoryRegion, 1);
MIPSCPU *cpu;
@@ -191,9 +192,8 @@ mips_mipssim_init(QEMUMachineInitArgs *args)
if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
/* Bail out if we have neither a kernel image nor boot vector code. */
fprintf(stderr,
- "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
+ "qemu: Warning, could not load MIPS bios '%s', and no -kernel argument was specified\n",
filename);
- exit(1);
} else {
/* We have a boot vector start address. */
env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
@@ -212,7 +212,9 @@ mips_mipssim_init(QEMUMachineInitArgs *args)
cpu_mips_clock_init(env);
/* Register 64 KB of ISA IO space at 0x1fd00000. */
- isa_mmio_init(0x1fd00000, 0x00010000);
+ memory_region_init_alias(isa, NULL, "isa_mmio",
+ get_system_io(), 0, 0x00010000);
+ memory_region_add_subregion(get_system_memory(), 0x1fd00000, isa);
/* A single 16450 sits at offset 0x3f8. It is attached to
MIPS CPU INT2, which is interrupt 4. */
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index 22beb0a67c..4bc2e3fa7a 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -164,6 +164,7 @@ void mips_r4k_init(QEMUMachineInitArgs *args)
MemoryRegion *ram = g_new(MemoryRegion, 1);
MemoryRegion *bios;
MemoryRegion *iomem = g_new(MemoryRegion, 1);
+ MemoryRegion *isa = g_new(MemoryRegion, 1);
int bios_size;
MIPSCPU *cpu;
CPUMIPSState *env;
@@ -273,7 +274,10 @@ void mips_r4k_init(QEMUMachineInitArgs *args)
rtc_init(isa_bus, 2000, NULL);
/* Register 64 KB of ISA IO space at 0x14000000 */
- isa_mmio_init(0x14000000, 0x00010000);
+ memory_region_init_alias(isa, NULL, "isa_mmio",
+ get_system_io(), 0, 0x00010000);
+ memory_region_add_subregion(get_system_memory(), 0x14000000, isa);
+
isa_mem_base = 0x10000000;
pit = pit_init(isa_bus, 0x40, 0, NULL);
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 3594b84259..4a74856c95 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -48,6 +48,10 @@
#define IVSHMEM_DPRINTF(fmt, ...)
#endif
+#define TYPE_IVSHMEM "ivshmem"
+#define IVSHMEM(obj) \
+ OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM)
+
typedef struct Peer {
int nb_eventfds;
EventNotifier *eventfds;
@@ -59,7 +63,10 @@ typedef struct EventfdEntry {
} EventfdEntry;
typedef struct IVShmemState {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
uint32_t intrmask;
uint32_t intrstatus;
uint32_t doorbell;
@@ -116,6 +123,7 @@ static inline bool is_power_of_two(uint64_t x) {
/* accessing registers - based on rtl8139 */
static void ivshmem_update_irq(IVShmemState *s, int val)
{
+ PCIDevice *d = PCI_DEVICE(s);
int isr;
isr = (s->intrstatus & s->intrmask) & 0xffffffff;
@@ -125,7 +133,7 @@ static void ivshmem_update_irq(IVShmemState *s, int val)
isr ? 1 : 0, s->intrstatus, s->intrmask);
}
- qemu_set_irq(s->dev.irq[0], (isr != 0));
+ qemu_set_irq(d->irq[0], (isr != 0));
}
static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
@@ -296,7 +304,7 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
/* if MSI is supported we need multiple interrupts */
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- s->eventfd_table[vector].pdev = &s->dev;
+ s->eventfd_table[vector].pdev = PCI_DEVICE(s);
s->eventfd_table[vector].vector = vector;
qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
@@ -341,11 +349,11 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd) {
memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
s->ivshmem_size, ptr);
- vmstate_register_ram(&s->ivshmem, &s->dev.qdev);
+ vmstate_register_ram(&s->ivshmem, DEVICE(s));
memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
/* region for shared memory */
- pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar);
+ pci_register_bar(PCI_DEVICE(s), 2, s->ivshmem_attr, &s->bar);
}
static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
@@ -469,7 +477,7 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
incoming_fd, 0);
memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s),
"ivshmem.bar2", s->ivshmem_size, map_ptr);
- vmstate_register_ram(&s->ivshmem, &s->dev.qdev);
+ vmstate_register_ram(&s->ivshmem, DEVICE(s));
IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
s->ivshmem_offset, s->ivshmem_size);
@@ -521,20 +529,21 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
* we just enable all vectors on init and after reset. */
static void ivshmem_use_msix(IVShmemState * s)
{
+ PCIDevice *d = PCI_DEVICE(s);
int i;
- if (!msix_present(&s->dev)) {
+ if (!msix_present(d)) {
return;
}
for (i = 0; i < s->vectors; i++) {
- msix_vector_use(&s->dev, i);
+ msix_vector_use(d, i);
}
}
static void ivshmem_reset(DeviceState *d)
{
- IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
+ IVShmemState *s = IVSHMEM(d);
s->intrstatus = 0;
ivshmem_use_msix(s);
@@ -569,7 +578,7 @@ static uint64_t ivshmem_get_size(IVShmemState * s) {
static void ivshmem_setup_msi(IVShmemState * s)
{
- if (msix_init_exclusive_bar(&s->dev, s->vectors, 1)) {
+ if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
IVSHMEM_DPRINTF("msix initialization failed\n");
exit(1);
}
@@ -585,12 +594,13 @@ static void ivshmem_setup_msi(IVShmemState * s)
static void ivshmem_save(QEMUFile* f, void *opaque)
{
IVShmemState *proxy = opaque;
+ PCIDevice *pci_dev = PCI_DEVICE(proxy);
IVSHMEM_DPRINTF("ivshmem_save\n");
- pci_device_save(&proxy->dev, f);
+ pci_device_save(pci_dev, f);
if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
- msix_save(&proxy->dev, f);
+ msix_save(pci_dev, f);
} else {
qemu_put_be32(f, proxy->intrstatus);
qemu_put_be32(f, proxy->intrmask);
@@ -603,6 +613,7 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
IVSHMEM_DPRINTF("ivshmem_load\n");
IVShmemState *proxy = opaque;
+ PCIDevice *pci_dev = PCI_DEVICE(proxy);
int ret;
if (version_id > 0) {
@@ -614,13 +625,13 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
return -EINVAL;
}
- ret = pci_device_load(&proxy->dev, f);
+ ret = pci_device_load(pci_dev, f);
if (ret) {
return ret;
}
if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
- msix_load(&proxy->dev, f);
+ msix_load(pci_dev, f);
ivshmem_use_msix(proxy);
} else {
proxy->intrstatus = qemu_get_be32(f);
@@ -639,7 +650,7 @@ static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
static int pci_ivshmem_init(PCIDevice *dev)
{
- IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+ IVShmemState *s = IVSHMEM(dev);
uint8_t *pci_conf;
if (s->sizearg == NULL)
@@ -648,7 +659,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
s->ivshmem_size = ivshmem_get_size(s);
}
- register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
+ register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
dev);
/* IRQFD requires MSI */
@@ -678,7 +689,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
migrate_add_blocker(s->migration_blocker);
}
- pci_conf = s->dev.config;
+ pci_conf = dev->config;
pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
pci_config_set_interrupt_pin(pci_conf, 1);
@@ -689,7 +700,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
"ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
/* region for registers*/
- pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
&s->ivshmem_mmio);
memory_region_init(&s->bar, OBJECT(s), "ivshmem-bar2-container", s->ivshmem_size);
@@ -723,7 +734,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
/* allocate/initialize space for interrupt handling */
s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
- pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar);
+ pci_register_bar(dev, 2, s->ivshmem_attr, &s->bar);
s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
@@ -764,14 +775,14 @@ static int pci_ivshmem_init(PCIDevice *dev)
}
- s->dev.config_write = ivshmem_write_config;
+ dev->config_write = ivshmem_write_config;
return 0;
}
static void pci_ivshmem_uninit(PCIDevice *dev)
{
- IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+ IVShmemState *s = IVSHMEM(dev);
if (s->migration_blocker) {
migrate_del_blocker(s->migration_blocker);
@@ -780,10 +791,10 @@ static void pci_ivshmem_uninit(PCIDevice *dev)
memory_region_destroy(&s->ivshmem_mmio);
memory_region_del_subregion(&s->bar, &s->ivshmem);
- vmstate_unregister_ram(&s->ivshmem, &s->dev.qdev);
+ vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
memory_region_destroy(&s->ivshmem);
memory_region_destroy(&s->bar);
- unregister_savevm(&dev->qdev, "ivshmem", s);
+ unregister_savevm(DEVICE(dev), "ivshmem", s);
}
static Property ivshmem_properties[] = {
@@ -813,7 +824,7 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ivshmem_info = {
- .name = "ivshmem",
+ .name = TYPE_IVSHMEM,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(IVShmemState),
.class_init = ivshmem_class_init,
diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c
index 699a16ffbe..5867c70069 100644
--- a/hw/misc/pc-testdev.c
+++ b/hw/misc/pc-testdev.c
@@ -49,6 +49,7 @@ typedef struct PCTestdev {
ISADevice parent_obj;
MemoryRegion ioport;
+ MemoryRegion ioport_byte;
MemoryRegion flush;
MemoryRegion irq;
MemoryRegion iomem;
@@ -80,13 +81,20 @@ static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data,
unsigned len)
{
PCTestdev *dev = opaque;
- dev->ioport_data = data;
+ int bits = len * 8;
+ int start_bit = (addr & 3) * 8;
+ uint32_t mask = ((uint32_t)-1 >> (32 - bits)) << start_bit;
+ dev->ioport_data &= ~mask;
+ dev->ioport_data |= data << start_bit;
}
static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len)
{
PCTestdev *dev = opaque;
- return dev->ioport_data;
+ int bits = len * 8;
+ int start_bit = (addr & 3) * 8;
+ uint32_t mask = ((uint32_t)-1 >> (32 - bits)) << start_bit;
+ return (dev->ioport_data & mask) >> start_bit;
}
static const MemoryRegionOps test_ioport_ops = {
@@ -95,6 +103,16 @@ static const MemoryRegionOps test_ioport_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static const MemoryRegionOps test_ioport_byte_ops = {
+ .read = test_ioport_read,
+ .write = test_ioport_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 1,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
static void test_flush_page(void *opaque, hwaddr addr, uint64_t data,
unsigned len)
{
@@ -122,7 +140,6 @@ static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len)
PCTestdev *dev = opaque;
uint64_t ret = 0;
memcpy(&ret, &dev->iomem_buf[addr], len);
- ret = le64_to_cpu(ret);
return ret;
}
@@ -131,7 +148,6 @@ static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned len)
{
PCTestdev *dev = opaque;
- val = cpu_to_le64(val);
memcpy(&dev->iomem_buf[addr], &val, len);
dev->iomem_buf[addr] = val;
}
@@ -151,6 +167,9 @@ static void testdev_realizefn(DeviceState *d, Error **errp)
memory_region_init_io(&dev->ioport, OBJECT(dev), &test_ioport_ops, dev,
"pc-testdev-ioport", 4);
+ memory_region_init_io(&dev->ioport_byte, OBJECT(dev),
+ &test_ioport_byte_ops, dev,
+ "pc-testdev-ioport-byte", 4);
memory_region_init_io(&dev->flush, OBJECT(dev), &test_flush_ops, dev,
"pc-testdev-flush-page", 4);
memory_region_init_io(&dev->irq, OBJECT(dev), &test_irq_ops, dev,
@@ -160,6 +179,7 @@ static void testdev_realizefn(DeviceState *d, Error **errp)
memory_region_add_subregion(io, 0xe0, &dev->ioport);
memory_region_add_subregion(io, 0xe4, &dev->flush);
+ memory_region_add_subregion(io, 0xe8, &dev->ioport_byte);
memory_region_add_subregion(io, 0x2000, &dev->irq);
memory_region_add_subregion(mem, 0xff000000, &dev->iomem);
}
diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c
index 8b0b73f9c4..d69ff3364d 100644
--- a/hw/misc/pci-testdev.c
+++ b/hw/misc/pci-testdev.c
@@ -76,13 +76,21 @@ enum {
#define IOTEST_ACCESS_WIDTH (sizeof(uint8_t))
typedef struct PCITestDevState {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
MemoryRegion mmio;
MemoryRegion portio;
IOTest *tests;
int current;
} PCITestDevState;
+#define TYPE_PCI_TEST_DEV "pci-testdev"
+
+#define PCI_TEST_DEV(obj) \
+ OBJECT_CHECK(PCITestDevState, (obj), TYPE_PCI_TEST_DEV)
+
#define IOTEST_IS_MEM(i) (strcmp(IOTEST_TYPE(i), "portio"))
#define IOTEST_REGION(d, i) (IOTEST_IS_MEM(i) ? &(d)->mmio : &(d)->portio)
#define IOTEST_SIZE(i) (IOTEST_IS_MEM(i) ? IOTEST_MEMSIZE : IOTEST_IOSIZE)
@@ -227,12 +235,12 @@ static const MemoryRegionOps pci_testdev_pio_ops = {
static int pci_testdev_init(PCIDevice *pci_dev)
{
- PCITestDevState *d = DO_UPCAST(PCITestDevState, dev, pci_dev);
+ PCITestDevState *d = PCI_TEST_DEV(pci_dev);
uint8_t *pci_conf;
char *name;
int r, i;
- pci_conf = d->dev.config;
+ pci_conf = pci_dev->config;
pci_conf[PCI_INTERRUPT_PIN] = 0; /* no interrupt pin */
@@ -240,8 +248,8 @@ static int pci_testdev_init(PCIDevice *pci_dev)
"pci-testdev-mmio", IOTEST_MEMSIZE * 2);
memory_region_init_io(&d->portio, OBJECT(d), &pci_testdev_pio_ops, d,
"pci-testdev-portio", IOTEST_IOSIZE * 2);
- pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
- pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->portio);
+ pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
+ pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->portio);
d->current = -1;
d->tests = g_malloc0(IOTEST_MAX * sizeof *d->tests);
@@ -274,7 +282,7 @@ static int pci_testdev_init(PCIDevice *pci_dev)
static void
pci_testdev_uninit(PCIDevice *dev)
{
- PCITestDevState *d = DO_UPCAST(PCITestDevState, dev, dev);
+ PCITestDevState *d = PCI_TEST_DEV(dev);
int i;
pci_testdev_reset(d);
@@ -291,7 +299,7 @@ pci_testdev_uninit(PCIDevice *dev)
static void qdev_pci_testdev_reset(DeviceState *dev)
{
- PCITestDevState *d = DO_UPCAST(PCITestDevState, dev.qdev, dev);
+ PCITestDevState *d = PCI_TEST_DEV(dev);
pci_testdev_reset(d);
}
@@ -311,7 +319,7 @@ static void pci_testdev_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo pci_testdev_info = {
- .name = "pci-testdev",
+ .name = TYPE_PCI_TEST_DEV,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCITestDevState),
.class_init = pci_testdev_class_init,
diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c
index d274fb4a87..00d9542c0b 100644
--- a/hw/misc/slavio_misc.c
+++ b/hw/misc/slavio_misc.c
@@ -368,7 +368,7 @@ static void slavio_led_mem_writew(void *opaque, hwaddr addr,
{
MiscState *s = opaque;
- trace_slavio_led_mem_readw(val & 0xffff);
+ trace_slavio_led_mem_writew(val & 0xffff);
switch (addr) {
case 0:
s->leds = val;
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index 540c377f61..ad8ce770dc 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -59,8 +59,23 @@ typedef struct VFIOQuirk {
MemoryRegion mem;
struct VFIODevice *vdev;
QLIST_ENTRY(VFIOQuirk) next;
- uint32_t data;
- uint32_t data2;
+ struct {
+ uint32_t base_offset:TARGET_PAGE_BITS;
+ uint32_t address_offset:TARGET_PAGE_BITS;
+ uint32_t address_size:3;
+ uint32_t bar:3;
+
+ uint32_t address_match;
+ uint32_t address_mask;
+
+ uint32_t address_val:TARGET_PAGE_BITS;
+ uint32_t data_offset:TARGET_PAGE_BITS;
+ uint32_t data_size:3;
+
+ uint8_t flags;
+ uint8_t read_flags;
+ uint8_t write_flags;
+ } data;
} VFIOQuirk;
typedef struct VFIOBAR {
@@ -72,6 +87,8 @@ typedef struct VFIOBAR {
size_t size;
uint32_t flags; /* VFIO region flags (rd/wr/mmap) */
uint8_t nr; /* cache the BAR number for debug */
+ bool ioport;
+ bool mem64;
QLIST_HEAD(, VFIOQuirk) quirks;
} VFIOBAR;
@@ -158,6 +175,7 @@ typedef struct VFIODevice {
PCIHostDeviceAddress host;
QLIST_ENTRY(VFIODevice) next;
struct VFIOGroup *group;
+ EventNotifier err_notifier;
uint32_t features;
#define VFIO_FEATURE_ENABLE_VGA_BIT 0
#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
@@ -165,6 +183,7 @@ typedef struct VFIODevice {
uint8_t pm_cap;
bool reset_works;
bool has_vga;
+ bool pci_aer;
} VFIODevice;
typedef struct VFIOGroup {
@@ -1097,251 +1116,315 @@ static const MemoryRegionOps vfio_vga_ops = {
* Device specific quirks
*/
-#define PCI_VENDOR_ID_ATI 0x1002
+/* Is range1 fully contained within range2? */
+static bool vfio_range_contained(uint64_t first1, uint64_t len1,
+ uint64_t first2, uint64_t len2) {
+ return (first1 >= first2 && first1 + len1 <= first2 + len2);
+}
-/*
- * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon
- * HD 5450/6350]) reports the upper byte of the physical address of the
- * I/O port BAR4 through VGA register 0x3c3. The BAR is 256 bytes, so the
- * lower byte is known to be zero. Probing for this quirk reads 0xff from
- * port 0x3c3 on some devices so we store the physical address and replace
- * reads with the virtual address any time it matches. XXX Research when
- * to enable quirk.
- */
-static uint64_t vfio_ati_3c3_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
+static bool vfio_flags_enabled(uint8_t flags, uint8_t mask)
+{
+ return (mask && (flags & mask) == mask);
+}
+
+static uint64_t vfio_generic_window_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
{
VFIOQuirk *quirk = opaque;
VFIODevice *vdev = quirk->vdev;
- PCIDevice *pdev = &vdev->pdev;
- uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
- addr + 0x3, size);
+ uint64_t data;
+
+ if (vfio_flags_enabled(quirk->data.flags, quirk->data.read_flags) &&
+ ranges_overlap(addr, size,
+ quirk->data.data_offset, quirk->data.data_size)) {
+ hwaddr offset = addr - quirk->data.data_offset;
- if (data == quirk->data) {
- data = pci_get_byte(pdev->config + PCI_BASE_ADDRESS_4 + 1);
- DPRINTF("%s(0x3c3, 1) = 0x%"PRIx64"\n", __func__, data);
+ if (!vfio_range_contained(addr, size, quirk->data.data_offset,
+ quirk->data.data_size)) {
+ hw_error("%s: window data read not fully contained: %s\n",
+ __func__, memory_region_name(&quirk->mem));
+ }
+
+ data = vfio_pci_read_config(&vdev->pdev,
+ quirk->data.address_val + offset, size);
+
+ DPRINTF("%s read(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%"
+ PRIx64"\n", memory_region_name(&quirk->mem), vdev->host.domain,
+ vdev->host.bus, vdev->host.slot, vdev->host.function,
+ quirk->data.bar, addr, size, data);
+ } else {
+ data = vfio_bar_read(&vdev->bars[quirk->data.bar],
+ addr + quirk->data.base_offset, size);
}
return data;
}
-static const MemoryRegionOps vfio_ati_3c3_quirk = {
- .read = vfio_ati_3c3_quirk_read,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
+static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
{
- PCIDevice *pdev = &vdev->pdev;
- off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_4;
- uint32_t physbar;
- VFIOQuirk *quirk;
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
- if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI ||
- vdev->bars[4].size < 256) {
- return;
- }
+ if (ranges_overlap(addr, size,
+ quirk->data.address_offset, quirk->data.address_size)) {
- /* Get I/O port BAR physical address */
- if (pread(vdev->fd, &physbar, 4, physoffset) != 4) {
- error_report("vfio: probe failed for ATI/AMD 0x3c3 quirk on device "
- "%04x:%02x:%02x.%x", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
- return;
+ if (addr != quirk->data.address_offset) {
+ hw_error("%s: offset write into address window: %s\n",
+ __func__, memory_region_name(&quirk->mem));
+ }
+
+ if ((data & ~quirk->data.address_mask) == quirk->data.address_match) {
+ quirk->data.flags |= quirk->data.write_flags |
+ quirk->data.read_flags;
+ quirk->data.address_val = data & quirk->data.address_mask;
+ } else {
+ quirk->data.flags &= ~(quirk->data.write_flags |
+ quirk->data.read_flags);
+ }
}
- quirk = g_malloc0(sizeof(*quirk));
- quirk->vdev = vdev;
- quirk->data = (physbar >> 8) & 0xff;
+ if (vfio_flags_enabled(quirk->data.flags, quirk->data.write_flags) &&
+ ranges_overlap(addr, size,
+ quirk->data.data_offset, quirk->data.data_size)) {
+ hwaddr offset = addr - quirk->data.data_offset;
- memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, quirk,
- "vfio-ati-3c3-quirk", 1);
- memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 3,
- &quirk->mem);
+ if (!vfio_range_contained(addr, size, quirk->data.data_offset,
+ quirk->data.data_size)) {
+ hw_error("%s: window data write not fully contained: %s\n",
+ __func__, memory_region_name(&quirk->mem));
+ }
- QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
- quirk, next);
+ vfio_pci_write_config(&vdev->pdev,
+ quirk->data.address_val + offset, data, size);
+ DPRINTF("%s write(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"
+ PRIx64", %d)\n", memory_region_name(&quirk->mem),
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function, quirk->data.bar, addr, data, size);
+ return;
+ }
- DPRINTF("Enabled ATI/AMD quirk 0x3c3 for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ vfio_bar_write(&vdev->bars[quirk->data.bar],
+ addr + quirk->data.base_offset, data, size);
}
-/*
- * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon
- * HD 5450/6350]) reports the physical address of MMIO BAR0 through a
- * write/read operation on I/O port BAR4. When uint32_t 0x4010 is written
- * to offset 0x0, the subsequent read from offset 0x4 returns the contents
- * of BAR0. Test for this quirk on all ATI/AMD devices. XXX - Note that
- * 0x10 is the offset of BAR0 in config sapce, is this a window to all of
- * config space?
- */
-static uint64_t vfio_ati_4010_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
+static const MemoryRegionOps vfio_generic_window_quirk = {
+ .read = vfio_generic_window_quirk_read,
+ .write = vfio_generic_window_quirk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t vfio_generic_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
{
VFIOQuirk *quirk = opaque;
VFIODevice *vdev = quirk->vdev;
- PCIDevice *pdev = &vdev->pdev;
- uint64_t data = vfio_bar_read(&vdev->bars[4], addr, size);
+ hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
+ hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK;
+ uint64_t data;
- if (addr == 4 && size == 4 && quirk->data) {
- data = pci_get_long(pdev->config + PCI_BASE_ADDRESS_0);
- DPRINTF("%s(BAR4+0x4) = 0x%"PRIx64"\n", __func__, data);
- }
+ if (vfio_flags_enabled(quirk->data.flags, quirk->data.read_flags) &&
+ ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) {
+ if (!vfio_range_contained(addr, size, offset,
+ quirk->data.address_mask + 1)) {
+ hw_error("%s: read not fully contained: %s\n",
+ __func__, memory_region_name(&quirk->mem));
+ }
- quirk->data = 0;
+ data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
+
+ DPRINTF("%s read(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%"
+ PRIx64"\n", memory_region_name(&quirk->mem), vdev->host.domain,
+ vdev->host.bus, vdev->host.slot, vdev->host.function,
+ quirk->data.bar, addr + base, size, data);
+ } else {
+ data = vfio_bar_read(&vdev->bars[quirk->data.bar], addr + base, size);
+ }
return data;
}
-static void vfio_ati_4010_quirk_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
+static void vfio_generic_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
{
VFIOQuirk *quirk = opaque;
VFIODevice *vdev = quirk->vdev;
+ hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
+ hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK;
+
+ if (vfio_flags_enabled(quirk->data.flags, quirk->data.write_flags) &&
+ ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) {
+ if (!vfio_range_contained(addr, size, offset,
+ quirk->data.address_mask + 1)) {
+ hw_error("%s: write not fully contained: %s\n",
+ __func__, memory_region_name(&quirk->mem));
+ }
+
+ vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
+
+ DPRINTF("%s write(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"
+ PRIx64", %d)\n", memory_region_name(&quirk->mem),
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function, quirk->data.bar, addr + base, data, size);
+ } else {
+ vfio_bar_write(&vdev->bars[quirk->data.bar], addr + base, data, size);
+ }
+}
- vfio_bar_write(&vdev->bars[4], addr, data, size);
+static const MemoryRegionOps vfio_generic_quirk = {
+ .read = vfio_generic_quirk_read,
+ .write = vfio_generic_quirk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+#define PCI_VENDOR_ID_ATI 0x1002
+
+/*
+ * Radeon HD cards (HD5450 & HD7850) report the upper byte of the I/O port BAR
+ * through VGA register 0x3c3. On newer cards, the I/O port BAR is always
+ * BAR4 (older cards like the X550 used BAR1, but we don't care to support
+ * those). Note that on bare metal, a read of 0x3c3 doesn't always return the
+ * I/O port BAR address. Originally this was coded to return the virtual BAR
+ * address only if the physical register read returns the actual BAR address,
+ * but users have reported greater success if we return the virtual address
+ * unconditionally.
+ */
+static uint64_t vfio_ati_3c3_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ uint64_t data = vfio_pci_read_config(&vdev->pdev,
+ PCI_BASE_ADDRESS_0 + (4 * 4) + 1,
+ size);
+ DPRINTF("%s(0x3c3, 1) = 0x%"PRIx64"\n", __func__, data);
- quirk->data = (addr == 0 && size == 4 && data == 0x4010) ? 1 : 0;
+ return data;
}
-static const MemoryRegionOps vfio_ati_4010_quirk = {
- .read = vfio_ati_4010_quirk_read,
- .write = vfio_ati_4010_quirk_write,
+static const MemoryRegionOps vfio_ati_3c3_quirk = {
+ .read = vfio_ati_3c3_quirk_read,
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void vfio_probe_ati_4010_quirk(VFIODevice *vdev, int nr)
+static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
- off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0;
- uint32_t physbar0;
- uint64_t data;
VFIOQuirk *quirk;
- if (!vdev->has_vga || nr != 4 || !vdev->bars[0].size ||
- pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
+ if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
return;
}
- /* Get I/O port BAR physical address */
- if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) {
- error_report("vfio: probe failed for ATI/AMD 0x4010 quirk on device "
- "%04x:%02x:%02x.%x", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
- return;
- }
-
- /* Write 0x4010 to I/O port BAR offset 0 */
- vfio_bar_write(&vdev->bars[4], 0, 0x4010, 4);
- /* Read back result */
- data = vfio_bar_read(&vdev->bars[4], 4, 4);
-
- /* If the register matches the physical address of BAR0, we need a quirk */
- if (data != physbar0) {
+ /*
+ * As long as the BAR is >= 256 bytes it will be aligned such that the
+ * lower byte is always zero. Filter out anything else, if it exists.
+ */
+ if (!vdev->bars[4].ioport || vdev->bars[4].size < 256) {
return;
}
quirk = g_malloc0(sizeof(*quirk));
quirk->vdev = vdev;
- memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_ati_4010_quirk, quirk,
- "vfio-ati-4010-quirk", 8);
- memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+ memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, quirk,
+ "vfio-ati-3c3-quirk", 1);
+ memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
+ 3 /* offset 3 bytes from 0x3c0 */, &quirk->mem);
- QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+ QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
+ quirk, next);
- DPRINTF("Enabled ATI/AMD quirk 0x4010 for device %04x:%02x:%02x.%x\n",
+ DPRINTF("Enabled ATI/AMD quirk 0x3c3 BAR4for device %04x:%02x:%02x.%x\n",
vdev->host.domain, vdev->host.bus, vdev->host.slot,
vdev->host.function);
}
/*
- * Device 1002:5b63 (Advanced Micro Devices [AMD] nee ATI RV370 [Radeon X550])
- * retrieves the upper half of the MMIO BAR0 physical address by writing
- * 0xf10 to I/O port BAR1 offset 0 and reading the result from offset 6.
- * XXX - 0x10 is the offset of BAR0 in PCI config space, this could provide
- * full access to config space. Config space is little endian, so the data
- * register probably starts at 0x4.
+ * Newer ATI/AMD devices, including HD5450 and HD7850, have a window to PCI
+ * config space through MMIO BAR2 at offset 0x4000. Nothing seems to access
+ * the MMIO space directly, but a window to this space is provided through
+ * I/O port BAR4. Offset 0x0 is the address register and offset 0x4 is the
+ * data register. When the address is programmed to a range of 0x4000-0x4fff
+ * PCI configuration space is available. Experimentation seems to indicate
+ * that only read-only access is provided, but we drop writes when the window
+ * is enabled to config space nonetheless.
*/
-static uint64_t vfio_ati_f10_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
+static void vfio_probe_ati_bar4_window_quirk(VFIODevice *vdev, int nr)
{
- VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
PCIDevice *pdev = &vdev->pdev;
- uint64_t data = vfio_bar_read(&vdev->bars[1], addr, size);
+ VFIOQuirk *quirk;
- if (addr == 6 && size == 2 && quirk->data) {
- data = pci_get_word(pdev->config + PCI_BASE_ADDRESS_0 + 2);
- DPRINTF("%s(BAR1+0x6) = 0x%"PRIx64"\n", __func__, data);
+ if (!vdev->has_vga || nr != 4 ||
+ pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
+ return;
}
- quirk->data = 0;
-
- return data;
-}
-
-static void vfio_ati_f10_quirk_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ quirk = g_malloc0(sizeof(*quirk));
+ quirk->vdev = vdev;
+ quirk->data.address_size = 4;
+ quirk->data.data_offset = 4;
+ quirk->data.data_size = 4;
+ quirk->data.address_match = 0x4000;
+ quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
+ quirk->data.bar = nr;
+ quirk->data.read_flags = quirk->data.write_flags = 1;
+
+ memory_region_init_io(&quirk->mem, OBJECT(vdev),
+ &vfio_generic_window_quirk, quirk,
+ "vfio-ati-bar4-window-quirk", 8);
+ memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ quirk->data.base_offset, &quirk->mem, 1);
- vfio_bar_write(&vdev->bars[1], addr, data, size);
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- quirk->data = (addr == 0 && size == 4 && data == 0xf10) ? 1 : 0;
+ DPRINTF("Enabled ATI/AMD BAR4 window quirk for device %04x:%02x:%02x.%x\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
}
-static const MemoryRegionOps vfio_ati_f10_quirk = {
- .read = vfio_ati_f10_quirk_read,
- .write = vfio_ati_f10_quirk_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_ati_f10_quirk(VFIODevice *vdev, int nr)
+/*
+ * Trap the BAR2 MMIO window to config space as well.
+ */
+static void vfio_probe_ati_bar2_4000_quirk(VFIODevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
- off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0;
- uint32_t physbar0;
- uint64_t data;
VFIOQuirk *quirk;
- if (!vdev->has_vga || nr != 1 || !vdev->bars[0].size ||
+ /* Only enable on newer devices where BAR2 is 64bit */
+ if (!vdev->has_vga || nr != 2 || !vdev->bars[2].mem64 ||
pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
return;
}
- /* Get I/O port BAR physical address */
- if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) {
- error_report("vfio: probe failed for ATI/AMD 0xf10 quirk on device "
- "%04x:%02x:%02x.%x", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
- return;
- }
-
- vfio_bar_write(&vdev->bars[1], 0, 0xf10, 4);
- data = vfio_bar_read(&vdev->bars[1], 0x6, 2);
-
- /* If the register matches the physical address of BAR0, we need a quirk */
- if (data != (le32_to_cpu(physbar0) >> 16)) {
- return;
- }
-
quirk = g_malloc0(sizeof(*quirk));
quirk->vdev = vdev;
-
- memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_ati_f10_quirk, quirk,
- "vfio-ati-f10-quirk", 8);
- memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+ quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1;
+ quirk->data.address_match = 0x4000;
+ quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
+ quirk->data.bar = nr;
+
+ memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk, quirk,
+ "vfio-ati-bar2-4000-quirk",
+ TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
+ memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ quirk->data.address_match & TARGET_PAGE_MASK,
+ &quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- DPRINTF("Enabled ATI/AMD quirk 0xf10 for device %04x:%02x:%02x.%x\n",
+ DPRINTF("Enabled ATI/AMD BAR2 0x4000 quirk for device %04x:%02x:%02x.%x\n",
vdev->host.domain, vdev->host.bus, vdev->host.slot,
vdev->host.function);
}
+/*
+ * Older ATI/AMD cards like the X550 have a similar window to that above.
+ * I/O port BAR1 provides a window to a mirror of PCI config space located
+ * in BAR2 at offset 0xf00. We don't care to support such older cards, but
+ * note it for future reference.
+ */
+
#define PCI_VENDOR_ID_NVIDIA 0x10de
/*
@@ -1360,7 +1443,7 @@ static void vfio_probe_ati_f10_quirk(VFIODevice *vdev, int nr)
* that use the I/O port BAR5 window but it doesn't hurt to leave it.
*/
enum {
- NV_3D0_NONE,
+ NV_3D0_NONE = 0,
NV_3D0_SELECT,
NV_3D0_WINDOW,
NV_3D0_READ,
@@ -1374,14 +1457,14 @@ static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque,
VFIODevice *vdev = quirk->vdev;
PCIDevice *pdev = &vdev->pdev;
uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
- addr + 0x10, size);
+ addr + quirk->data.base_offset, size);
- if (quirk->data == NV_3D0_READ && addr == 0) {
- data = vfio_pci_read_config(pdev, quirk->data2, size);
+ if (quirk->data.flags == NV_3D0_READ && addr == quirk->data.data_offset) {
+ data = vfio_pci_read_config(pdev, quirk->data.address_val, size);
DPRINTF("%s(0x3d0, %d) = 0x%"PRIx64"\n", __func__, size, data);
}
- quirk->data = NV_3D0_NONE;
+ quirk->data.flags = NV_3D0_NONE;
return data;
}
@@ -1393,43 +1476,42 @@ static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
VFIODevice *vdev = quirk->vdev;
PCIDevice *pdev = &vdev->pdev;
- switch (quirk->data) {
+ switch (quirk->data.flags) {
case NV_3D0_NONE:
- if (addr == 4 && data == 0x338) {
- quirk->data = NV_3D0_SELECT;
+ if (addr == quirk->data.address_offset && data == 0x338) {
+ quirk->data.flags = NV_3D0_SELECT;
}
break;
case NV_3D0_SELECT:
- quirk->data = NV_3D0_NONE;
- if (addr == 0 && (data & ~0xff) == 0x1800) {
- quirk->data = NV_3D0_WINDOW;
- quirk->data2 = data & 0xff;
+ quirk->data.flags = NV_3D0_NONE;
+ if (addr == quirk->data.data_offset &&
+ (data & ~quirk->data.address_mask) == quirk->data.address_match) {
+ quirk->data.flags = NV_3D0_WINDOW;
+ quirk->data.address_val = data & quirk->data.address_mask;
}
break;
case NV_3D0_WINDOW:
- quirk->data = NV_3D0_NONE;
- if (addr == 4) {
+ quirk->data.flags = NV_3D0_NONE;
+ if (addr == quirk->data.address_offset) {
if (data == 0x538) {
- quirk->data = NV_3D0_READ;
+ quirk->data.flags = NV_3D0_READ;
} else if (data == 0x738) {
- quirk->data = NV_3D0_WRITE;
+ quirk->data.flags = NV_3D0_WRITE;
}
}
break;
case NV_3D0_WRITE:
- quirk->data = NV_3D0_NONE;
- if (addr == 0) {
- vfio_pci_write_config(pdev, quirk->data2, data, size);
+ quirk->data.flags = NV_3D0_NONE;
+ if (addr == quirk->data.data_offset) {
+ vfio_pci_write_config(pdev, quirk->data.address_val, data, size);
DPRINTF("%s(0x3d0, 0x%"PRIx64", %d)\n", __func__, data, size);
return;
}
break;
- default:
- quirk->data = NV_3D0_NONE;
}
vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
- addr + 0x10, data, size);
+ addr + quirk->data.base_offset, data, size);
}
static const MemoryRegionOps vfio_nvidia_3d0_quirk = {
@@ -1450,11 +1532,18 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIODevice *vdev)
quirk = g_malloc0(sizeof(*quirk));
quirk->vdev = vdev;
-
- memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_3d0_quirk, quirk,
- "vfio-nvidia-3d0-quirk", 6);
+ quirk->data.base_offset = 0x10;
+ quirk->data.address_offset = 4;
+ quirk->data.address_size = 2;
+ quirk->data.address_match = 0x1800;
+ quirk->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1;
+ quirk->data.data_offset = 0;
+ quirk->data.data_size = 4;
+
+ memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_3d0_quirk,
+ quirk, "vfio-nvidia-3d0-quirk", 6);
memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
- 0x10, &quirk->mem);
+ quirk->data.base_offset, &quirk->mem);
QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
quirk, next);
@@ -1478,76 +1567,46 @@ enum {
NV_BAR5_VALID = 0x7,
};
-static uint64_t vfio_nvidia_bar5_window_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
- uint64_t data = vfio_bar_read(&vdev->bars[5], addr, size);
-
- if (addr == 0xc && quirk->data == NV_BAR5_VALID) {
- data = vfio_pci_read_config(&vdev->pdev, quirk->data2, size);
- DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", %d) = 0x%"
- PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function, addr, size, data);
- }
-
- return data;
-}
-
static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
- /*
- * Use quirk->data to track enables and quirk->data2 for the offset
- */
switch (addr) {
case 0x0:
if (data & 0x1) {
- quirk->data |= NV_BAR5_MASTER;
+ quirk->data.flags |= NV_BAR5_MASTER;
} else {
- quirk->data &= ~NV_BAR5_MASTER;
+ quirk->data.flags &= ~NV_BAR5_MASTER;
}
break;
case 0x4:
if (data & 0x1) {
- quirk->data |= NV_BAR5_ENABLE;
+ quirk->data.flags |= NV_BAR5_ENABLE;
} else {
- quirk->data &= ~NV_BAR5_ENABLE;
+ quirk->data.flags &= ~NV_BAR5_ENABLE;
}
break;
case 0x8:
- if (quirk->data & NV_BAR5_MASTER) {
+ if (quirk->data.flags & NV_BAR5_MASTER) {
if ((data & ~0xfff) == 0x88000) {
- quirk->data |= NV_BAR5_ADDRESS;
- quirk->data2 = data & 0xfff;
+ quirk->data.flags |= NV_BAR5_ADDRESS;
+ quirk->data.address_val = data & 0xfff;
} else if ((data & ~0xff) == 0x1800) {
- quirk->data |= NV_BAR5_ADDRESS;
- quirk->data2 = data & 0xff;
+ quirk->data.flags |= NV_BAR5_ADDRESS;
+ quirk->data.address_val = data & 0xff;
} else {
- quirk->data &= ~NV_BAR5_ADDRESS;
+ quirk->data.flags &= ~NV_BAR5_ADDRESS;
}
}
break;
- case 0xc:
- if (quirk->data == NV_BAR5_VALID) {
- vfio_pci_write_config(&vdev->pdev, quirk->data2, data, size);
- DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", 0x%"
- PRIx64", %d)\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function,
- addr, data, size);
- return;
- }
}
- vfio_bar_write(&vdev->bars[5], addr, data, size);
+ vfio_generic_window_quirk_write(opaque, addr, data, size);
}
static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = {
- .read = vfio_nvidia_bar5_window_quirk_read,
+ .read = vfio_generic_window_quirk_read,
.write = vfio_nvidia_bar5_window_quirk_write,
.valid.min_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,
@@ -1565,8 +1624,15 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
quirk = g_malloc0(sizeof(*quirk));
quirk->vdev = vdev;
-
- memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_bar5_window_quirk, quirk,
+ quirk->data.read_flags = quirk->data.write_flags = NV_BAR5_VALID;
+ quirk->data.address_offset = 0x8;
+ quirk->data.address_size = 0; /* actually 4, but avoids generic code */
+ quirk->data.data_offset = 0xc;
+ quirk->data.data_size = 4;
+ quirk->data.bar = nr;
+
+ memory_region_init_io(&quirk->mem, OBJECT(vdev),
+ &vfio_nvidia_bar5_window_quirk, quirk,
"vfio-nvidia-bar5-window-quirk", 16);
memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
@@ -1586,51 +1652,6 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
*
* Here's offset 0x88000...
*/
-static uint64_t vfio_nvidia_bar0_88000_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
- hwaddr base = 0x88000 & TARGET_PAGE_MASK;
- hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK;
- uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size);
-
- if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
- data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
-
- DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%"
- PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function, addr + base, size, data);
- }
-
- return data;
-}
-
-static void vfio_nvidia_bar0_88000_quirk_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
- hwaddr base = 0x88000 & TARGET_PAGE_MASK;
- hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK;
-
- if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
- vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
-
- DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%"
- PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function, addr + base, data, size);
- } else {
- vfio_bar_write(&vdev->bars[0], addr + base, data, size);
- }
-}
-
-static const MemoryRegionOps vfio_nvidia_bar0_88000_quirk = {
- .read = vfio_nvidia_bar0_88000_quirk_read,
- .write = vfio_nvidia_bar0_88000_quirk_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
@@ -1643,13 +1664,17 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
quirk = g_malloc0(sizeof(*quirk));
quirk->vdev = vdev;
-
- memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_bar0_88000_quirk, quirk,
- "vfio-nvidia-bar0-88000-quirk",
- TARGET_PAGE_ALIGN(PCIE_CONFIG_SPACE_SIZE));
+ quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1;
+ quirk->data.address_match = 0x88000;
+ quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
+ quirk->data.bar = nr;
+
+ memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk,
+ quirk, "vfio-nvidia-bar0-88000-quirk",
+ TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
- 0x88000 & TARGET_PAGE_MASK,
- &quirk->mem, 1);
+ quirk->data.address_match & TARGET_PAGE_MASK,
+ &quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
@@ -1661,51 +1686,6 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
/*
* And here's the same for BAR0 offset 0x1800...
*/
-static uint64_t vfio_nvidia_bar0_1800_quirk_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
- hwaddr base = 0x1800 & TARGET_PAGE_MASK;
- hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK;
- uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size);
-
- if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
- data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
-
- DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%"
- PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function, addr + base, size, data);
- }
-
- return data;
-}
-
-static void vfio_nvidia_bar0_1800_quirk_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
- hwaddr base = 0x1800 & TARGET_PAGE_MASK;
- hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK;
-
- if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
- vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
-
- DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%"
- PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function, addr + base, data, size);
- } else {
- vfio_bar_write(&vdev->bars[0], addr + base, data, size);
- }
-}
-
-static const MemoryRegionOps vfio_nvidia_bar0_1800_quirk = {
- .read = vfio_nvidia_bar0_1800_quirk_read,
- .write = vfio_nvidia_bar0_1800_quirk_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
@@ -1722,13 +1702,17 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
quirk = g_malloc0(sizeof(*quirk));
quirk->vdev = vdev;
+ quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1;
+ quirk->data.address_match = 0x1800;
+ quirk->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1;
+ quirk->data.bar = nr;
- memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_bar0_1800_quirk, quirk,
+ memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk, quirk,
"vfio-nvidia-bar0-1800-quirk",
- TARGET_PAGE_ALIGN(PCI_CONFIG_SPACE_SIZE));
+ TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
- 0x1800 & TARGET_PAGE_MASK,
- &quirk->mem, 1);
+ quirk->data.address_match & TARGET_PAGE_MASK,
+ &quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
@@ -1768,8 +1752,8 @@ static void vfio_vga_quirk_teardown(VFIODevice *vdev)
static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr)
{
- vfio_probe_ati_4010_quirk(vdev, nr);
- vfio_probe_ati_f10_quirk(vdev, nr);
+ vfio_probe_ati_bar4_window_quirk(vdev, nr);
+ vfio_probe_ati_bar2_4000_quirk(vdev, nr);
vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
@@ -2270,11 +2254,14 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
}
pci_bar = le32_to_cpu(pci_bar);
- type = pci_bar & (pci_bar & PCI_BASE_ADDRESS_SPACE_IO ?
- ~PCI_BASE_ADDRESS_IO_MASK : ~PCI_BASE_ADDRESS_MEM_MASK);
+ bar->ioport = (pci_bar & PCI_BASE_ADDRESS_SPACE_IO);
+ bar->mem64 = bar->ioport ? 0 : (pci_bar & PCI_BASE_ADDRESS_MEM_TYPE_64);
+ type = pci_bar & (bar->ioport ? ~PCI_BASE_ADDRESS_IO_MASK :
+ ~PCI_BASE_ADDRESS_MEM_MASK);
/* A "slow" read/write mapping underlies all BARs */
- memory_region_init_io(&bar->mem, OBJECT(vdev), &vfio_bar_ops, bar, name, size);
+ memory_region_init_io(&bar->mem, OBJECT(vdev), &vfio_bar_ops,
+ bar, name, size);
pci_register_bar(&vdev->pdev, nr, type, &bar->mem);
/*
@@ -2781,6 +2768,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
{
struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
+ struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) };
int ret, i;
ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
@@ -2924,6 +2912,19 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
vdev->has_vga = true;
}
+ irq_info.index = VFIO_PCI_ERR_IRQ_INDEX;
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
+ if (ret) {
+ /* This can fail for an old kernel or legacy PCI dev */
+ DPRINTF("VFIO_DEVICE_GET_IRQ_INFO failure ret=%d\n", ret);
+ ret = 0;
+ } else if (irq_info.count == 1) {
+ vdev->pci_aer = true;
+ } else {
+ error_report("vfio: Warning: "
+ "Could not enable error recovery for the device\n");
+ }
error:
if (ret) {
@@ -2946,6 +2947,113 @@ static void vfio_put_device(VFIODevice *vdev)
}
}
+static void vfio_err_notifier_handler(void *opaque)
+{
+ VFIODevice *vdev = opaque;
+
+ if (!event_notifier_test_and_clear(&vdev->err_notifier)) {
+ return;
+ }
+
+ /*
+ * TBD. Retrieve the error details and decide what action
+ * needs to be taken. One of the actions could be to pass
+ * the error to the guest and have the guest driver recover
+ * from the error. This requires that PCIe capabilities be
+ * exposed to the guest. For now, we just terminate the
+ * guest to contain the error.
+ */
+
+ error_report("%s (%04x:%02x:%02x.%x)"
+ "Unrecoverable error detected...\n"
+ "Please collect any data possible and then kill the guest",
+ __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function);
+
+ vm_stop(RUN_STATE_IO_ERROR);
+}
+
+/*
+ * Registers error notifier for devices supporting error recovery.
+ * If we encounter a failure in this function, we report an error
+ * and continue after disabling error recovery support for the
+ * device.
+ */
+static void vfio_register_err_notifier(VFIODevice *vdev)
+{
+ int ret;
+ int argsz;
+ struct vfio_irq_set *irq_set;
+ int32_t *pfd;
+
+ if (!vdev->pci_aer) {
+ return;
+ }
+
+ if (event_notifier_init(&vdev->err_notifier, 0)) {
+ error_report("vfio: Warning: "
+ "Unable to init event notifier for error detection\n");
+ vdev->pci_aer = false;
+ return;
+ }
+
+ argsz = sizeof(*irq_set) + sizeof(*pfd);
+
+ irq_set = g_malloc0(argsz);
+ irq_set->argsz = argsz;
+ irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
+ VFIO_IRQ_SET_ACTION_TRIGGER;
+ irq_set->index = VFIO_PCI_ERR_IRQ_INDEX;
+ irq_set->start = 0;
+ irq_set->count = 1;
+ pfd = (int32_t *)&irq_set->data;
+
+ *pfd = event_notifier_get_fd(&vdev->err_notifier);
+ qemu_set_fd_handler(*pfd, vfio_err_notifier_handler, NULL, vdev);
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ if (ret) {
+ error_report("vfio: Failed to set up error notification\n");
+ qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
+ event_notifier_cleanup(&vdev->err_notifier);
+ vdev->pci_aer = false;
+ }
+ g_free(irq_set);
+}
+
+static void vfio_unregister_err_notifier(VFIODevice *vdev)
+{
+ int argsz;
+ struct vfio_irq_set *irq_set;
+ int32_t *pfd;
+ int ret;
+
+ if (!vdev->pci_aer) {
+ return;
+ }
+
+ argsz = sizeof(*irq_set) + sizeof(*pfd);
+
+ irq_set = g_malloc0(argsz);
+ irq_set->argsz = argsz;
+ irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
+ VFIO_IRQ_SET_ACTION_TRIGGER;
+ irq_set->index = VFIO_PCI_ERR_IRQ_INDEX;
+ irq_set->start = 0;
+ irq_set->count = 1;
+ pfd = (int32_t *)&irq_set->data;
+ *pfd = -1;
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ if (ret) {
+ error_report("vfio: Failed to de-assign error fd: %d\n", ret);
+ }
+ g_free(irq_set);
+ qemu_set_fd_handler(event_notifier_get_fd(&vdev->err_notifier),
+ NULL, NULL, vdev);
+ event_notifier_cleanup(&vdev->err_notifier);
+}
+
static int vfio_initfn(PCIDevice *pdev)
{
VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
@@ -3078,6 +3186,7 @@ static int vfio_initfn(PCIDevice *pdev)
}
add_boot_device_path(vdev->bootindex, &pdev->qdev, NULL);
+ vfio_register_err_notifier(vdev);
return 0;
@@ -3097,6 +3206,7 @@ static void vfio_exitfn(PCIDevice *pdev)
VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
VFIOGroup *group = vdev->group;
+ vfio_unregister_err_notifier(vdev);
pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
vfio_disable_interrupts(vdev);
if (vdev->intx.mmap_timer) {
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 5f04f135af..b952d8d0f3 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -85,7 +85,10 @@ enum {
};
typedef struct E1000State_st {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
NICState *nic;
NICConf conf;
MemoryRegion mmio;
@@ -138,6 +141,11 @@ typedef struct E1000State_st {
uint32_t compat_flags;
} E1000State;
+#define TYPE_E1000 "e1000"
+
+#define E1000(obj) \
+ OBJECT_CHECK(E1000State, (obj), TYPE_E1000)
+
#define defreg(x) x = (E1000_##x>>2)
enum {
defreg(CTRL), defreg(EECD), defreg(EERD), defreg(GPRC),
@@ -240,6 +248,8 @@ static const uint32_t mac_reg_init[] = {
static void
set_interrupt_cause(E1000State *s, int index, uint32_t val)
{
+ PCIDevice *d = PCI_DEVICE(s);
+
if (val && (E1000_DEVID >= E1000_DEV_ID_82547EI_MOBILE)) {
/* Only for 8257x */
val |= E1000_ICR_INT_ASSERTED;
@@ -256,7 +266,7 @@ set_interrupt_cause(E1000State *s, int index, uint32_t val)
*/
s->mac_reg[ICS] = val;
- qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
+ qemu_set_irq(d->irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
}
static void
@@ -553,6 +563,7 @@ xmit_seg(E1000State *s)
static void
process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
{
+ PCIDevice *d = PCI_DEVICE(s);
uint32_t txd_lower = le32_to_cpu(dp->lower.data);
uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
unsigned int split_size = txd_lower & 0xffff, bytes, sz, op;
@@ -610,7 +621,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
bytes = msh - tp->size;
bytes = MIN(sizeof(tp->data) - tp->size, bytes);
- pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
+ pci_dma_read(d, addr, tp->data + tp->size, bytes);
sz = tp->size + bytes;
if (sz >= tp->hdr_len && tp->size < tp->hdr_len) {
memmove(tp->header, tp->data, tp->hdr_len);
@@ -628,7 +639,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
DBGOUT(TXERR, "TCP segmentation error\n");
} else {
split_size = MIN(sizeof(tp->data) - tp->size, split_size);
- pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
+ pci_dma_read(d, addr, tp->data + tp->size, split_size);
tp->size += split_size;
}
@@ -647,6 +658,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
static uint32_t
txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
{
+ PCIDevice *d = PCI_DEVICE(s);
uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS)))
@@ -654,7 +666,7 @@ txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
dp->upper.data = cpu_to_le32(txd_upper);
- pci_dma_write(&s->dev, base + ((char *)&dp->upper - (char *)dp),
+ pci_dma_write(d, base + ((char *)&dp->upper - (char *)dp),
&dp->upper, sizeof(dp->upper));
return E1000_ICR_TXDW;
}
@@ -670,6 +682,7 @@ static uint64_t tx_desc_base(E1000State *s)
static void
start_xmit(E1000State *s)
{
+ PCIDevice *d = PCI_DEVICE(s);
dma_addr_t base;
struct e1000_tx_desc desc;
uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
@@ -682,7 +695,7 @@ start_xmit(E1000State *s)
while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
base = tx_desc_base(s) +
sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
- pci_dma_read(&s->dev, base, &desc, sizeof(desc));
+ pci_dma_read(d, base, &desc, sizeof(desc));
DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
(void *)(intptr_t)desc.buffer_addr, desc.lower.data,
@@ -815,6 +828,7 @@ static ssize_t
e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
E1000State *s = qemu_get_nic_opaque(nc);
+ PCIDevice *d = PCI_DEVICE(s);
struct e1000_rx_desc desc;
dma_addr_t base;
unsigned int n, rdt;
@@ -874,7 +888,7 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
desc_size = s->rxbuf_size;
}
base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
- pci_dma_read(&s->dev, base, &desc, sizeof(desc));
+ pci_dma_read(d, base, &desc, sizeof(desc));
desc.special = vlan_special;
desc.status |= (vlan_status | E1000_RXD_STAT_DD);
if (desc.buffer_addr) {
@@ -883,7 +897,7 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
if (copy_size > s->rxbuf_size) {
copy_size = s->rxbuf_size;
}
- pci_dma_write(&s->dev, le64_to_cpu(desc.buffer_addr),
+ pci_dma_write(d, le64_to_cpu(desc.buffer_addr),
buf + desc_offset + vlan_offset, copy_size);
}
desc_offset += desc_size;
@@ -898,7 +912,7 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
} else { // as per intel docs; skip descriptors with null buf addr
DBGOUT(RX, "Null RX descriptor!!\n");
}
- pci_dma_write(&s->dev, base, &desc, sizeof(desc));
+ pci_dma_write(d, base, &desc, sizeof(desc));
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
s->mac_reg[RDH] = 0;
@@ -1184,7 +1198,7 @@ static const VMStateDescription vmstate_e1000 = {
.pre_save = e1000_pre_save,
.post_load = e1000_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, E1000State),
+ VMSTATE_PCI_DEVICE(parent_obj, E1000State),
VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */
VMSTATE_UNUSED(4), /* Was mmio_base. */
VMSTATE_UINT32(rxbuf_size, E1000State),
@@ -1298,7 +1312,7 @@ e1000_cleanup(NetClientState *nc)
static void
pci_e1000_uninit(PCIDevice *dev)
{
- E1000State *d = DO_UPCAST(E1000State, dev, dev);
+ E1000State *d = E1000(dev);
qemu_del_timer(d->autoneg_timer);
qemu_free_timer(d->autoneg_timer);
@@ -1318,13 +1332,14 @@ static NetClientInfo net_e1000_info = {
static int pci_e1000_init(PCIDevice *pci_dev)
{
- E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
+ DeviceState *dev = DEVICE(pci_dev);
+ E1000State *d = E1000(pci_dev);
uint8_t *pci_conf;
uint16_t checksum = 0;
int i;
uint8_t *macaddr;
- pci_conf = d->dev.config;
+ pci_conf = pci_dev->config;
/* TODO: RST# value should be 0, PCI spec 6.2.4 */
pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
@@ -1333,9 +1348,9 @@ static int pci_e1000_init(PCIDevice *pci_dev)
e1000_mmio_setup(d);
- pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
+ pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
- pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
+ pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
memmove(d->eeprom_data, e1000_eeprom_template,
sizeof e1000_eeprom_template);
@@ -1349,11 +1364,11 @@ static int pci_e1000_init(PCIDevice *pci_dev)
d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
- object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
+ object_get_typename(OBJECT(d)), dev->id, d);
qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
- add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
+ add_boot_device_path(d->conf.bootindex, dev, "/ethernet-phy@0");
d->autoneg_timer = qemu_new_timer_ms(vm_clock, e1000_autoneg_timer, d);
@@ -1362,7 +1377,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
static void qdev_e1000_reset(DeviceState *dev)
{
- E1000State *d = DO_UPCAST(E1000State, dev.qdev, dev);
+ E1000State *d = E1000(dev);
e1000_reset(d);
}
@@ -1392,7 +1407,7 @@ static void e1000_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo e1000_info = {
- .name = "e1000",
+ .name = TYPE_E1000,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(E1000State),
.class_init = e1000_class_init,
diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c
index 2ef4ac3299..becd26c5d5 100644
--- a/hw/net/milkymist-minimac2.c
+++ b/hw/net/milkymist-minimac2.c
@@ -355,7 +355,7 @@ minimac2_write(void *opaque, hwaddr addr, uint64_t value,
{
MilkymistMinimac2State *s = opaque;
- trace_milkymist_minimac2_memory_read(addr, value);
+ trace_milkymist_minimac2_memory_write(addr, value);
addr >>= 2;
switch (addr) {
diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c
index f4a5aef426..6ef28f77a2 100644
--- a/hw/net/pcnet-pci.c
+++ b/hw/net/pcnet-pci.c
@@ -43,9 +43,16 @@
//#define PCNET_DEBUG_TMD
//#define PCNET_DEBUG_MATCH
+#define TYPE_PCI_PCNET "pcnet"
+
+#define PCI_PCNET(obj) \
+ OBJECT_CHECK(PCIPCNetState, (obj), TYPE_PCI_PCNET)
typedef struct {
- PCIDevice pci_dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
PCNetState state;
MemoryRegion io_bar;
} PCIPCNetState;
@@ -236,7 +243,7 @@ static const VMStateDescription vmstate_pci_pcnet = {
.minimum_version_id = 2,
.minimum_version_id_old = 2,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
+ VMSTATE_PCI_DEVICE(parent_obj, PCIPCNetState),
VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
VMSTATE_END_OF_LIST()
}
@@ -273,7 +280,7 @@ static void pci_pcnet_cleanup(NetClientState *nc)
static void pci_pcnet_uninit(PCIDevice *dev)
{
- PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
+ PCIPCNetState *d = PCI_PCNET(dev);
memory_region_destroy(&d->state.mmio);
memory_region_destroy(&d->io_bar);
@@ -293,7 +300,7 @@ static NetClientInfo net_pci_pcnet_info = {
static int pci_pcnet_init(PCIDevice *pci_dev)
{
- PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+ PCIPCNetState *d = PCI_PCNET(pci_dev);
PCNetState *s = &d->state;
uint8_t *pci_conf;
@@ -329,12 +336,12 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
s->phys_mem_write = pci_physical_memory_write;
s->dma_opaque = pci_dev;
- return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
+ return pcnet_common_init(DEVICE(pci_dev), s, &net_pci_pcnet_info);
}
static void pci_reset(DeviceState *dev)
{
- PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
+ PCIPCNetState *d = PCI_PCNET(dev);
pcnet_h_reset(&d->state);
}
@@ -362,7 +369,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo pcnet_info = {
- .name = "pcnet",
+ .name = TYPE_PCI_PCNET,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIPCNetState),
.class_init = pcnet_class_init,
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index a00ff581dc..65520340fc 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -92,6 +92,11 @@ static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)
}
#endif
+#define TYPE_RTL8139 "rtl8139"
+
+#define RTL8139(obj) \
+ OBJECT_CHECK(RTL8139State, (obj), TYPE_RTL8139)
+
/* Symbolic offsets to registers. */
enum RTL8139_registers {
MAC0 = 0, /* Ethernet hardware address. */
@@ -428,7 +433,10 @@ typedef struct RTL8139TallyCounters
static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
typedef struct RTL8139State {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
uint8_t phys[8]; /* mac address */
uint8_t mult[8]; /* multicast mask array */
@@ -701,13 +709,14 @@ static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
static void rtl8139_update_irq(RTL8139State *s)
{
+ PCIDevice *d = PCI_DEVICE(s);
int isr;
isr = (s->IntrStatus & s->IntrMask) & 0xffff;
DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus,
s->IntrMask);
- qemu_set_irq(s->dev.irq[0], (isr != 0));
+ qemu_set_irq(d->irq[0], (isr != 0));
}
static int rtl8139_RxWrap(RTL8139State *s)
@@ -738,6 +747,8 @@ static int rtl8139_cp_transmitter_enabled(RTL8139State *s)
static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
{
+ PCIDevice *d = PCI_DEVICE(s);
+
if (s->RxBufAddr + size > s->RxBufferSize)
{
int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
@@ -749,14 +760,14 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
if (size > wrapped)
{
- pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
+ pci_dma_write(d, s->RxBuf + s->RxBufAddr,
buf, size-wrapped);
}
/* reset buffer pointer */
s->RxBufAddr = 0;
- pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
+ pci_dma_write(d, s->RxBuf + s->RxBufAddr,
buf + (size-wrapped), wrapped);
s->RxBufAddr = wrapped;
@@ -766,7 +777,7 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
}
/* non-wrapping path or overwrapping enabled */
- pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, buf, size);
+ pci_dma_write(d, s->RxBuf + s->RxBufAddr, buf, size);
s->RxBufAddr += size;
}
@@ -809,6 +820,7 @@ static int rtl8139_can_receive(NetClientState *nc)
static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
{
RTL8139State *s = qemu_get_nic_opaque(nc);
+ PCIDevice *d = PCI_DEVICE(s);
/* size is the length of the buffer passed to the driver */
int size = size_;
const uint8_t *dot1q_buf = NULL;
@@ -973,13 +985,13 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
- pci_dma_read(&s->dev, cplus_rx_ring_desc, &val, 4);
+ pci_dma_read(d, cplus_rx_ring_desc, &val, 4);
rxdw0 = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_rx_ring_desc+4, &val, 4);
+ pci_dma_read(d, cplus_rx_ring_desc+4, &val, 4);
rxdw1 = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_rx_ring_desc+8, &val, 4);
+ pci_dma_read(d, cplus_rx_ring_desc+8, &val, 4);
rxbufLO = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_rx_ring_desc+12, &val, 4);
+ pci_dma_read(d, cplus_rx_ring_desc+12, &val, 4);
rxbufHI = le32_to_cpu(val);
DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
@@ -1047,12 +1059,12 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* receive/copy to target memory */
if (dot1q_buf) {
- pci_dma_write(&s->dev, rx_addr, buf, 2 * ETHER_ADDR_LEN);
- pci_dma_write(&s->dev, rx_addr + 2 * ETHER_ADDR_LEN,
+ pci_dma_write(d, rx_addr, buf, 2 * ETHER_ADDR_LEN);
+ pci_dma_write(d, rx_addr + 2 * ETHER_ADDR_LEN,
buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
size - 2 * ETHER_ADDR_LEN);
} else {
- pci_dma_write(&s->dev, rx_addr, buf, size);
+ pci_dma_write(d, rx_addr, buf, size);
}
if (s->CpCmd & CPlusRxChkSum)
@@ -1062,7 +1074,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* write checksum */
val = cpu_to_le32(crc32(0, buf, size_));
- pci_dma_write(&s->dev, rx_addr+size, (uint8_t *)&val, 4);
+ pci_dma_write(d, rx_addr+size, (uint8_t *)&val, 4);
/* first segment of received packet flag */
#define CP_RX_STATUS_FS (1<<29)
@@ -1108,9 +1120,9 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* update ring data */
val = cpu_to_le32(rxdw0);
- pci_dma_write(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4);
+ pci_dma_write(d, cplus_rx_ring_desc, (uint8_t *)&val, 4);
val = cpu_to_le32(rxdw1);
- pci_dma_write(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
+ pci_dma_write(d, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
/* update tally counter */
++s->tally_counters.RxOk;
@@ -1197,7 +1209,7 @@ static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
static void rtl8139_reset(DeviceState *d)
{
- RTL8139State *s = container_of(d, RTL8139State, dev.qdev);
+ RTL8139State *s = RTL8139(d);
int i;
/* restore MAC address */
@@ -1293,49 +1305,50 @@ static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr)
{
+ PCIDevice *d = PCI_DEVICE(s);
RTL8139TallyCounters *tally_counters = &s->tally_counters;
uint16_t val16;
uint32_t val32;
uint64_t val64;
val64 = cpu_to_le64(tally_counters->TxOk);
- pci_dma_write(&s->dev, tc_addr + 0, (uint8_t *)&val64, 8);
+ pci_dma_write(d, tc_addr + 0, (uint8_t *)&val64, 8);
val64 = cpu_to_le64(tally_counters->RxOk);
- pci_dma_write(&s->dev, tc_addr + 8, (uint8_t *)&val64, 8);
+ pci_dma_write(d, tc_addr + 8, (uint8_t *)&val64, 8);
val64 = cpu_to_le64(tally_counters->TxERR);
- pci_dma_write(&s->dev, tc_addr + 16, (uint8_t *)&val64, 8);
+ pci_dma_write(d, tc_addr + 16, (uint8_t *)&val64, 8);
val32 = cpu_to_le32(tally_counters->RxERR);
- pci_dma_write(&s->dev, tc_addr + 24, (uint8_t *)&val32, 4);
+ pci_dma_write(d, tc_addr + 24, (uint8_t *)&val32, 4);
val16 = cpu_to_le16(tally_counters->MissPkt);
- pci_dma_write(&s->dev, tc_addr + 28, (uint8_t *)&val16, 2);
+ pci_dma_write(d, tc_addr + 28, (uint8_t *)&val16, 2);
val16 = cpu_to_le16(tally_counters->FAE);
- pci_dma_write(&s->dev, tc_addr + 30, (uint8_t *)&val16, 2);
+ pci_dma_write(d, tc_addr + 30, (uint8_t *)&val16, 2);
val32 = cpu_to_le32(tally_counters->Tx1Col);
- pci_dma_write(&s->dev, tc_addr + 32, (uint8_t *)&val32, 4);
+ pci_dma_write(d, tc_addr + 32, (uint8_t *)&val32, 4);
val32 = cpu_to_le32(tally_counters->TxMCol);
- pci_dma_write(&s->dev, tc_addr + 36, (uint8_t *)&val32, 4);
+ pci_dma_write(d, tc_addr + 36, (uint8_t *)&val32, 4);
val64 = cpu_to_le64(tally_counters->RxOkPhy);
- pci_dma_write(&s->dev, tc_addr + 40, (uint8_t *)&val64, 8);
+ pci_dma_write(d, tc_addr + 40, (uint8_t *)&val64, 8);
val64 = cpu_to_le64(tally_counters->RxOkBrd);
- pci_dma_write(&s->dev, tc_addr + 48, (uint8_t *)&val64, 8);
+ pci_dma_write(d, tc_addr + 48, (uint8_t *)&val64, 8);
val32 = cpu_to_le32(tally_counters->RxOkMul);
- pci_dma_write(&s->dev, tc_addr + 56, (uint8_t *)&val32, 4);
+ pci_dma_write(d, tc_addr + 56, (uint8_t *)&val32, 4);
val16 = cpu_to_le16(tally_counters->TxAbt);
- pci_dma_write(&s->dev, tc_addr + 60, (uint8_t *)&val16, 2);
+ pci_dma_write(d, tc_addr + 60, (uint8_t *)&val16, 2);
val16 = cpu_to_le16(tally_counters->TxUndrn);
- pci_dma_write(&s->dev, tc_addr + 62, (uint8_t *)&val16, 2);
+ pci_dma_write(d, tc_addr + 62, (uint8_t *)&val16, 2);
}
/* Loads values of tally counters from VM state file */
@@ -1364,6 +1377,8 @@ static const VMStateDescription vmstate_tally_counters = {
static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
{
+ DeviceState *d = DEVICE(s);
+
val &= 0xff;
DPRINTF("ChipCmd write val=0x%08x\n", val);
@@ -1371,7 +1386,7 @@ static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
if (val & CmdReset)
{
DPRINTF("ChipCmd reset\n");
- rtl8139_reset(&s->dev.qdev);
+ rtl8139_reset(d);
}
if (val & CmdRxEnb)
{
@@ -1525,6 +1540,8 @@ static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s)
static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
{
+ DeviceState *d = DEVICE(s);
+
val &= 0xff;
DPRINTF("Cfg9346 write val=0x%02x\n", val);
@@ -1544,7 +1561,7 @@ static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
} else if (opmode == 0x40) {
/* Reset. */
val = 0;
- rtl8139_reset(&s->dev.qdev);
+ rtl8139_reset(d);
}
s->Cfg9346 = val;
@@ -1821,13 +1838,14 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
DPRINTF("+++ transmitting from descriptor %d\n", descriptor);
+ PCIDevice *d = PCI_DEVICE(s);
int txsize = s->TxStatus[descriptor] & 0x1fff;
uint8_t txbuffer[0x2000];
DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
txsize, s->TxAddr[descriptor]);
- pci_dma_read(&s->dev, s->TxAddr[descriptor], txbuffer, txsize);
+ pci_dma_read(d, s->TxAddr[descriptor], txbuffer, txsize);
/* Mark descriptor as transferred */
s->TxStatus[descriptor] |= TxHostOwns;
@@ -1946,6 +1964,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
return 0 ;
}
+ PCIDevice *d = PCI_DEVICE(s);
int descriptor = s->currCPlusTxDesc;
dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
@@ -1959,13 +1978,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
- pci_dma_read(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4);
+ pci_dma_read(d, cplus_tx_ring_desc, (uint8_t *)&val, 4);
txdw0 = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_tx_ring_desc+4, (uint8_t *)&val, 4);
+ pci_dma_read(d, cplus_tx_ring_desc+4, (uint8_t *)&val, 4);
txdw1 = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_tx_ring_desc+8, (uint8_t *)&val, 4);
+ pci_dma_read(d, cplus_tx_ring_desc+8, (uint8_t *)&val, 4);
txbufLO = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
+ pci_dma_read(d, cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
txbufHI = le32_to_cpu(val);
DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor,
@@ -2072,7 +2091,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
DMA_ADDR_FMT" to offset %d\n", txsize, tx_addr,
s->cplus_txbuffer_offset);
- pci_dma_read(&s->dev, tx_addr,
+ pci_dma_read(d, tx_addr,
s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
s->cplus_txbuffer_offset += txsize;
@@ -2100,7 +2119,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
/* update ring data */
val = cpu_to_le32(txdw0);
- pci_dma_write(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4);
+ pci_dma_write(d, cplus_tx_ring_desc, (uint8_t *)&val, 4);
/* Now decide if descriptor being processed is holding the last segment of packet */
if (txdw0 & CP_TX_LS)
@@ -3273,7 +3292,7 @@ static const VMStateDescription vmstate_rtl8139 = {
.post_load = rtl8139_post_load,
.pre_save = rtl8139_pre_save,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, RTL8139State),
+ VMSTATE_PCI_DEVICE(parent_obj, RTL8139State),
VMSTATE_PARTIAL_BUFFER(phys, RTL8139State, 6),
VMSTATE_BUFFER(mult, RTL8139State),
VMSTATE_UINT32_ARRAY(TxStatus, RTL8139State, 4),
@@ -3439,7 +3458,7 @@ static void rtl8139_cleanup(NetClientState *nc)
static void pci_rtl8139_uninit(PCIDevice *dev)
{
- RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev);
+ RTL8139State *s = RTL8139(dev);
memory_region_destroy(&s->bar_io);
memory_region_destroy(&s->bar_mem);
@@ -3477,10 +3496,11 @@ static NetClientInfo net_rtl8139_info = {
static int pci_rtl8139_init(PCIDevice *dev)
{
- RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev);
+ RTL8139State *s = RTL8139(dev);
+ DeviceState *d = DEVICE(dev);
uint8_t *pci_conf;
- pci_conf = s->dev.config;
+ pci_conf = dev->config;
pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
/* TODO: start of capability list, but no capability
* list bit in status register, and offset 0xdc seems unused. */
@@ -3490,8 +3510,8 @@ static int pci_rtl8139_init(PCIDevice *dev)
"rtl8139", 0x100);
memory_region_init_io(&s->bar_mem, OBJECT(s), &rtl8139_mmio_ops, s,
"rtl8139", 0x100);
- pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
- pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
@@ -3507,7 +3527,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), d->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
s->cplus_txbuffer = NULL;
@@ -3518,7 +3538,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
s->timer = qemu_new_timer_ns(vm_clock, rtl8139_timer, s);
rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
- add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet-phy@0");
+ add_boot_device_path(s->conf.bootindex, d, "/ethernet-phy@0");
return 0;
}
@@ -3546,7 +3566,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo rtl8139_info = {
- .name = "rtl8139",
+ .name = TYPE_RTL8139,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(RTL8139State),
.class_init = rtl8139_class_init,
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 1ea95564a5..679f50c33a 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -21,6 +21,8 @@
#include "hw/virtio/virtio-net.h"
#include "net/vhost_net.h"
#include "hw/virtio/virtio-bus.h"
+#include "qapi/qmp/qjson.h"
+#include "monitor/monitor.h"
#define VIRTIO_NET_VM_VERSION 11
@@ -192,6 +194,105 @@ static void virtio_net_set_link_status(NetClientState *nc)
virtio_net_set_status(vdev, vdev->status);
}
+static void rxfilter_notify(NetClientState *nc)
+{
+ QObject *event_data;
+ VirtIONet *n = qemu_get_nic_opaque(nc);
+
+ if (nc->rxfilter_notify_enabled) {
+ if (n->netclient_name) {
+ event_data = qobject_from_jsonf("{ 'name': %s, 'path': %s }",
+ n->netclient_name,
+ object_get_canonical_path(OBJECT(n->qdev)));
+ } else {
+ event_data = qobject_from_jsonf("{ 'path': %s }",
+ object_get_canonical_path(OBJECT(n->qdev)));
+ }
+ monitor_protocol_event(QEVENT_NIC_RX_FILTER_CHANGED, event_data);
+ qobject_decref(event_data);
+
+ /* disable event notification to avoid events flooding */
+ nc->rxfilter_notify_enabled = 0;
+ }
+}
+
+static char *mac_strdup_printf(const uint8_t *mac)
+{
+ return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", mac[0],
+ mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
+{
+ VirtIONet *n = qemu_get_nic_opaque(nc);
+ RxFilterInfo *info;
+ strList *str_list, *entry;
+ intList *int_list, *int_entry;
+ int i, j;
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(nc->name);
+ info->promiscuous = n->promisc;
+
+ if (n->nouni) {
+ info->unicast = RX_STATE_NONE;
+ } else if (n->alluni) {
+ info->unicast = RX_STATE_ALL;
+ } else {
+ info->unicast = RX_STATE_NORMAL;
+ }
+
+ if (n->nomulti) {
+ info->multicast = RX_STATE_NONE;
+ } else if (n->allmulti) {
+ info->multicast = RX_STATE_ALL;
+ } else {
+ info->multicast = RX_STATE_NORMAL;
+ }
+
+ info->broadcast_allowed = n->nobcast;
+ info->multicast_overflow = n->mac_table.multi_overflow;
+ info->unicast_overflow = n->mac_table.uni_overflow;
+
+ info->main_mac = mac_strdup_printf(n->mac);
+
+ str_list = NULL;
+ for (i = 0; i < n->mac_table.first_multi; i++) {
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
+ entry->next = str_list;
+ str_list = entry;
+ }
+ info->unicast_table = str_list;
+
+ str_list = NULL;
+ for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
+ entry->next = str_list;
+ str_list = entry;
+ }
+ info->multicast_table = str_list;
+
+ int_list = NULL;
+ for (i = 0; i < MAX_VLAN >> 5; i++) {
+ for (j = 0; n->vlans[i] && j < 0x1f; j++) {
+ if (n->vlans[i] & (1U << j)) {
+ int_entry = g_malloc0(sizeof(*int_entry));
+ int_entry->value = (i << 5) + j;
+ int_entry->next = int_list;
+ int_list = int_entry;
+ }
+ }
+ }
+ info->vlan_table = int_list;
+
+ /* enable event notification after query */
+ nc->rxfilter_notify_enabled = 1;
+
+ return info;
+}
+
static void virtio_net_reset(VirtIODevice *vdev)
{
VirtIONet *n = VIRTIO_NET(vdev);
@@ -420,6 +521,7 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
{
uint8_t on;
size_t s;
+ NetClientState *nc = qemu_get_queue(n->nic);
s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on));
if (s != sizeof(on)) {
@@ -442,6 +544,8 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_ERR;
}
+ rxfilter_notify(nc);
+
return VIRTIO_NET_OK;
}
@@ -487,6 +591,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
{
struct virtio_net_ctrl_mac mac_data;
size_t s;
+ NetClientState *nc = qemu_get_queue(n->nic);
if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) {
if (iov_size(iov, iov_cnt) != sizeof(n->mac)) {
@@ -495,6 +600,8 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac));
assert(s == sizeof(n->mac));
qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
+ rxfilter_notify(nc);
+
return VIRTIO_NET_OK;
}
@@ -512,19 +619,19 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
sizeof(mac_data.entries));
mac_data.entries = ldl_p(&mac_data.entries);
if (s != sizeof(mac_data.entries)) {
- return VIRTIO_NET_ERR;
+ goto error;
}
iov_discard_front(&iov, &iov_cnt, s);
if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) {
- return VIRTIO_NET_ERR;
+ goto error;
}
if (mac_data.entries <= MAC_TABLE_ENTRIES) {
s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
mac_data.entries * ETH_ALEN);
if (s != mac_data.entries * ETH_ALEN) {
- return VIRTIO_NET_ERR;
+ goto error;
}
n->mac_table.in_use += mac_data.entries;
} else {
@@ -539,27 +646,33 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
sizeof(mac_data.entries));
mac_data.entries = ldl_p(&mac_data.entries);
if (s != sizeof(mac_data.entries)) {
- return VIRTIO_NET_ERR;
+ goto error;
}
iov_discard_front(&iov, &iov_cnt, s);
if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) {
- return VIRTIO_NET_ERR;
+ goto error;
}
if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
mac_data.entries * ETH_ALEN);
if (s != mac_data.entries * ETH_ALEN) {
- return VIRTIO_NET_ERR;
+ goto error;
}
n->mac_table.in_use += mac_data.entries;
} else {
n->mac_table.multi_overflow = 1;
}
+ rxfilter_notify(nc);
+
return VIRTIO_NET_OK;
+
+error:
+ rxfilter_notify(nc);
+ return VIRTIO_NET_ERR;
}
static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
@@ -567,6 +680,7 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
{
uint16_t vid;
size_t s;
+ NetClientState *nc = qemu_get_queue(n->nic);
s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid));
vid = lduw_p(&vid);
@@ -584,6 +698,8 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
else
return VIRTIO_NET_ERR;
+ rxfilter_notify(nc);
+
return VIRTIO_NET_OK;
}
@@ -1312,6 +1428,7 @@ static NetClientInfo net_virtio_info = {
.receive = virtio_net_receive,
.cleanup = virtio_net_cleanup,
.link_status_changed = virtio_net_set_link_status,
+ .query_rx_filter = virtio_net_query_rxfilter,
};
static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
@@ -1373,6 +1490,7 @@ static int virtio_net_device_init(VirtIODevice *vdev)
DeviceState *qdev = DEVICE(vdev);
VirtIONet *n = VIRTIO_NET(vdev);
+ NetClientState *nc;
virtio_init(VIRTIO_DEVICE(n), "virtio-net", VIRTIO_ID_NET,
n->config_size);
@@ -1439,6 +1557,9 @@ static int virtio_net_device_init(VirtIODevice *vdev)
n->vlans = g_malloc0(MAX_VLAN >> 3);
+ nc = qemu_get_queue(n->nic);
+ nc->rxfilter_notify_enabled = 1;
+
n->qdev = qdev;
register_savevm(qdev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
virtio_net_save, virtio_net_load, n);
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index e455282365..0a35015b9e 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -35,6 +35,7 @@
#define TYPE_FW_CFG "fw_cfg"
#define FW_CFG_NAME "fw_cfg"
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
+#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
typedef struct FWCfgEntry {
uint32_t len;
@@ -44,7 +45,10 @@ typedef struct FWCfgEntry {
} FWCfgEntry;
struct FWCfgState {
- SysBusDevice busdev;
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
MemoryRegion ctl_iomem, data_iomem, comb_iomem;
uint32_t ctl_iobase, data_iobase;
FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
@@ -326,7 +330,7 @@ static const MemoryRegionOps fw_cfg_comb_mem_ops = {
static void fw_cfg_reset(DeviceState *d)
{
- FWCfgState *s = DO_UPCAST(FWCfgState, busdev.qdev, d);
+ FWCfgState *s = FW_CFG(d);
fw_cfg_select(s, 0);
}
@@ -489,12 +493,12 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
SysBusDevice *d;
FWCfgState *s;
- dev = qdev_create(NULL, "fw_cfg");
+ dev = qdev_create(NULL, TYPE_FW_CFG);
qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
qdev_prop_set_uint32(dev, "data_iobase", data_port);
d = SYS_BUS_DEVICE(dev);
- s = DO_UPCAST(FWCfgState, busdev.qdev, dev);
+ s = FW_CFG(dev);
assert(!object_resolve_path(FW_CFG_PATH, NULL));
@@ -522,31 +526,38 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
return s;
}
-static int fw_cfg_init1(SysBusDevice *dev)
+static void fw_cfg_initfn(Object *obj)
{
- FWCfgState *s = FROM_SYSBUS(FWCfgState, dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ FWCfgState *s = FW_CFG(obj);
memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops, s,
"fwcfg.ctl", FW_CFG_SIZE);
- sysbus_init_mmio(dev, &s->ctl_iomem);
+ sysbus_init_mmio(sbd, &s->ctl_iomem);
memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops, s,
"fwcfg.data", FW_CFG_DATA_SIZE);
- sysbus_init_mmio(dev, &s->data_iomem);
+ sysbus_init_mmio(sbd, &s->data_iomem);
/* In case ctl and data overlap: */
memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops, s,
"fwcfg", FW_CFG_SIZE);
+}
+
+static void fw_cfg_realize(DeviceState *dev, Error **errp)
+{
+ FWCfgState *s = FW_CFG(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
if (s->ctl_iobase + 1 == s->data_iobase) {
- sysbus_add_io(dev, s->ctl_iobase, &s->comb_iomem);
+ sysbus_add_io(sbd, s->ctl_iobase, &s->comb_iomem);
} else {
if (s->ctl_iobase) {
- sysbus_add_io(dev, s->ctl_iobase, &s->ctl_iomem);
+ sysbus_add_io(sbd, s->ctl_iobase, &s->ctl_iomem);
}
if (s->data_iobase) {
- sysbus_add_io(dev, s->data_iobase, &s->data_iomem);
+ sysbus_add_io(sbd, s->data_iobase, &s->data_iomem);
}
}
- return 0;
}
static Property fw_cfg_properties[] = {
@@ -557,16 +568,14 @@ static Property fw_cfg_properties[] = {
FWCfgState *fw_cfg_find(void)
{
- return OBJECT_CHECK(FWCfgState, object_resolve_path(FW_CFG_PATH, NULL),
- TYPE_FW_CFG);
+ return FW_CFG(object_resolve_path(FW_CFG_PATH, NULL));
}
static void fw_cfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = fw_cfg_init1;
+ dc->realize = fw_cfg_realize;
dc->no_user = 1;
dc->reset = fw_cfg_reset;
dc->vmsd = &vmstate_fw_cfg;
@@ -577,6 +586,7 @@ static const TypeInfo fw_cfg_info = {
.name = TYPE_FW_CFG,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(FWCfgState),
+ .instance_init = fw_cfg_initfn,
.class_init = fw_cfg_class_init,
};
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
index 924438bcc2..a08f27ce2e 100644
--- a/hw/openrisc/openrisc_sim.c
+++ b/hw/openrisc/openrisc_sim.c
@@ -82,7 +82,7 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
}
if (kernel_size < 0) {
- qemu_log("QEMU: couldn't load the kernel '%s'\n",
+ fprintf(stderr, "QEMU: couldn't load the kernel '%s'\n",
kernel_filename);
exit(1);
}
@@ -96,7 +96,7 @@ static void openrisc_sim_init(QEMUMachineInitArgs *args)
ram_addr_t ram_size = args->ram_size;
const char *cpu_model = args->cpu_model;
const char *kernel_filename = args->kernel_filename;
- OpenRISCCPU *cpu = NULL;
+ OpenRISCCPU *cpu = NULL;
MemoryRegion *ram;
int n;
@@ -107,7 +107,7 @@ static void openrisc_sim_init(QEMUMachineInitArgs *args)
for (n = 0; n < smp_cpus; n++) {
cpu = cpu_openrisc_init(cpu_model);
if (cpu == NULL) {
- qemu_log("Unable to find CPU definition!\n");
+ fprintf(stderr, "Unable to find CPU definition!\n");
exit(1);
}
qemu_register_reset(main_cpu_reset, cpu);
diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c
index 5807a92d7f..b98bfb0664 100644
--- a/hw/pci-bridge/i82801b11.c
+++ b/hw/pci-bridge/i82801b11.c
@@ -69,7 +69,7 @@ static int i82801b11_bridge_initfn(PCIDevice *d)
if (rc < 0) {
goto err_bridge;
}
- pci_config_set_prog_interface(d->config, PCI_CLASS_BRDIGE_PCI_INF_SUB);
+ pci_config_set_prog_interface(d->config, PCI_CLASS_BRIDGE_PCI_INF_SUB);
return 0;
err_bridge:
diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
index 06ace085b5..3756ce9a4b 100644
--- a/hw/pci-host/apb.c
+++ b/hw/pci-host/apb.c
@@ -70,9 +70,14 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
#define MAX_IVEC 0x40
#define NO_IRQ_REQUEST (MAX_IVEC + 1)
+#define TYPE_APB "pbm"
+
+#define APB_DEVICE(obj) \
+ OBJECT_CHECK(APBState, (obj), TYPE_APB)
+
typedef struct APBState {
- SysBusDevice busdev;
- PCIBus *bus;
+ PCIHostState parent_obj;
+
MemoryRegion apb_config;
MemoryRegion pci_config;
MemoryRegion pci_mmio;
@@ -284,10 +289,11 @@ static void apb_pci_config_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
APBState *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
val = qemu_bswap_len(val, size);
APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
- pci_data_write(s->bus, addr, val, size);
+ pci_data_write(phb->bus, addr, val, size);
}
static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
@@ -295,63 +301,14 @@ static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
{
uint32_t ret;
APBState *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
- ret = pci_data_read(s->bus, addr, size);
+ ret = pci_data_read(phb->bus, addr, size);
ret = qemu_bswap_len(ret, size);
APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, ret);
return ret;
}
-static void pci_apb_iowriteb (void *opaque, hwaddr addr,
- uint32_t val)
-{
- cpu_outb(addr & IOPORTS_MASK, val);
-}
-
-static void pci_apb_iowritew (void *opaque, hwaddr addr,
- uint32_t val)
-{
- cpu_outw(addr & IOPORTS_MASK, bswap16(val));
-}
-
-static void pci_apb_iowritel (void *opaque, hwaddr addr,
- uint32_t val)
-{
- cpu_outl(addr & IOPORTS_MASK, bswap32(val));
-}
-
-static uint32_t pci_apb_ioreadb (void *opaque, hwaddr addr)
-{
- uint32_t val;
-
- val = cpu_inb(addr & IOPORTS_MASK);
- return val;
-}
-
-static uint32_t pci_apb_ioreadw (void *opaque, hwaddr addr)
-{
- uint32_t val;
-
- val = bswap16(cpu_inw(addr & IOPORTS_MASK));
- return val;
-}
-
-static uint32_t pci_apb_ioreadl (void *opaque, hwaddr addr)
-{
- uint32_t val;
-
- val = bswap32(cpu_inl(addr & IOPORTS_MASK));
- return val;
-}
-
-static const MemoryRegionOps pci_ioport_ops = {
- .old_mmio = {
- .read = { pci_apb_ioreadb, pci_apb_ioreadw, pci_apb_ioreadl },
- .write = { pci_apb_iowriteb, pci_apb_iowritew, pci_apb_iowritel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
/* The APB host has an IRQ line for each IRQ line of each slot. */
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
{
@@ -431,12 +388,13 @@ PCIBus *pci_apb_init(hwaddr special_base,
{
DeviceState *dev;
SysBusDevice *s;
+ PCIHostState *phb;
APBState *d;
PCIDevice *pci_dev;
PCIBridge *br;
/* Ultrasparc PBM main bus */
- dev = qdev_create(NULL, "pbm");
+ dev = qdev_create(NULL, TYPE_APB);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
/* apb_config */
@@ -445,24 +403,25 @@ PCIBus *pci_apb_init(hwaddr special_base,
sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
/* pci_ioport */
sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
- d = FROM_SYSBUS(APBState, s);
+ d = APB_DEVICE(dev);
memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL);
memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio);
- d->bus = pci_register_bus(&d->busdev.qdev, "pci",
- pci_apb_set_irq, pci_pbm_map_irq, d,
- &d->pci_mmio,
- get_system_io(),
- 0, 32, TYPE_PCI_BUS);
+ phb = PCI_HOST_BRIDGE(dev);
+ phb->bus = pci_register_bus(DEVICE(phb), "pci",
+ pci_apb_set_irq, pci_pbm_map_irq, d,
+ &d->pci_mmio,
+ get_system_io(),
+ 0, 32, TYPE_PCI_BUS);
*pbm_irqs = d->pbm_irqs;
d->ivec_irqs = ivec_irqs;
- pci_create_simple(d->bus, 0, "pbm-pci");
+ pci_create_simple(phb->bus, 0, "pbm-pci");
/* APB secondary busses */
- pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
+ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
"pbm-bridge");
br = DO_UPCAST(PCIBridge, dev, pci_dev);
pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
@@ -470,7 +429,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
qdev_init_nofail(&pci_dev->qdev);
*bus2 = pci_bridge_get_sec_bus(br);
- pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
+ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true,
"pbm-bridge");
br = DO_UPCAST(PCIBridge, dev, pci_dev);
pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
@@ -478,13 +437,13 @@ PCIBus *pci_apb_init(hwaddr special_base,
qdev_init_nofail(&pci_dev->qdev);
*bus3 = pci_bridge_get_sec_bus(br);
- return d->bus;
+ return phb->bus;
}
static void pci_pbm_reset(DeviceState *d)
{
unsigned int i;
- APBState *s = container_of(d, APBState, busdev.qdev);
+ APBState *s = APB_DEVICE(d);
for (i = 0; i < 8; i++) {
s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
@@ -513,7 +472,7 @@ static int pci_pbm_init_device(SysBusDevice *dev)
APBState *s;
unsigned int i;
- s = FROM_SYSBUS(APBState, dev);
+ s = APB_DEVICE(dev);
for (i = 0; i < 8; i++) {
s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
}
@@ -536,8 +495,8 @@ static int pci_pbm_init_device(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->pci_config);
/* pci_ioport */
- memory_region_init_io(&s->pci_ioport, OBJECT(s), &pci_ioport_ops, s,
- "apb-pci-ioport", 0x10000);
+ memory_region_init_alias(&s->pci_ioport, OBJECT(s), "apb-pci-ioport",
+ get_system_io(), 0, 0x10000);
/* at region 2 */
sysbus_init_mmio(dev, &s->pci_ioport);
@@ -581,8 +540,8 @@ static void pbm_host_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo pbm_host_info = {
- .name = "pbm",
- .parent = TYPE_SYS_BUS_DEVICE,
+ .name = TYPE_APB,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(APBState),
.class_init = pbm_host_class_init,
};
diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c
index 592d6666bc..5086d42c13 100644
--- a/hw/pci-host/bonito.c
+++ b/hw/pci-host/bonito.c
@@ -210,14 +210,8 @@ typedef struct PCIBonitoState
MemoryRegion iomem;
MemoryRegion iomem_ldma;
MemoryRegion iomem_cop;
-
- hwaddr bonito_pciio_start;
- hwaddr bonito_pciio_length;
- int bonito_pciio_handle;
-
- hwaddr bonito_localio_start;
- hwaddr bonito_localio_length;
- int bonito_localio_handle;
+ MemoryRegion bonito_pciio;
+ MemoryRegion bonito_localio;
} PCIBonitoState;
@@ -750,15 +744,16 @@ static int bonito_initfn(PCIDevice *dev)
sysbus_mmio_map(sysbus, 4, 0xbfe00300);
/* Map PCI IO Space 0x1fd0 0000 - 0x1fd1 0000 */
- s->bonito_pciio_start = BONITO_PCIIO_BASE;
- s->bonito_pciio_length = BONITO_PCIIO_SIZE;
- isa_mem_base = s->bonito_pciio_start;
- isa_mmio_init(s->bonito_pciio_start, s->bonito_pciio_length);
+ memory_region_init_alias(&s->bonito_pciio, OBJECT(s), "isa_mmio",
+ get_system_io(), 0, BONITO_PCIIO_SIZE);
+ sysbus_init_mmio(sysbus, &s->bonito_pciio);
+ sysbus_mmio_map(sysbus, 5, BONITO_PCIIO_BASE);
/* add pci local io mapping */
- s->bonito_localio_start = BONITO_DEV_BASE;
- s->bonito_localio_length = BONITO_DEV_SIZE;
- isa_mmio_init(s->bonito_localio_start, s->bonito_localio_length);
+ memory_region_init_alias(&s->bonito_localio, OBJECT(s), "isa_mmio",
+ get_system_io(), 0, BONITO_DEV_SIZE);
+ sysbus_init_mmio(sysbus, &s->bonito_localio);
+ sysbus_mmio_map(sysbus, 6, BONITO_DEV_BASE);
/* set the default value of north bridge pci config */
pci_set_word(dev->config + PCI_COMMAND, 0x0000);
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 870e38810c..39088603bb 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -87,7 +87,10 @@ typedef struct PIIX3State {
OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
struct PCII440FXState {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
MemoryRegion *system_memory;
MemoryRegion *pci_address_space;
MemoryRegion *ram_memory;
@@ -121,22 +124,24 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
static void i440fx_update_memory_mappings(PCII440FXState *d)
{
int i;
+ PCIDevice *pd = PCI_DEVICE(d);
memory_region_transaction_begin();
for (i = 0; i < 13; i++) {
pam_update(&d->pam_regions[i], i,
- d->dev.config[I440FX_PAM + ((i + 1) / 2)]);
+ pd->config[I440FX_PAM + ((i + 1) / 2)]);
}
- smram_update(&d->smram_region, d->dev.config[I440FX_SMRAM], d->smm_enabled);
+ smram_update(&d->smram_region, pd->config[I440FX_SMRAM], d->smm_enabled);
memory_region_transaction_commit();
}
static void i440fx_set_smm(int val, void *arg)
{
PCII440FXState *d = arg;
+ PCIDevice *pd = PCI_DEVICE(d);
memory_region_transaction_begin();
- smram_set_smm(&d->smm_enabled, val, d->dev.config[I440FX_SMRAM],
+ smram_set_smm(&d->smm_enabled, val, pd->config[I440FX_SMRAM],
&d->smram_region);
memory_region_transaction_commit();
}
@@ -158,9 +163,10 @@ static void i440fx_write_config(PCIDevice *dev,
static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
{
PCII440FXState *d = opaque;
+ PCIDevice *pd = PCI_DEVICE(d);
int ret, i;
- ret = pci_device_load(&d->dev, f);
+ ret = pci_device_load(pd, f);
if (ret < 0)
return ret;
i440fx_update_memory_mappings(d);
@@ -191,34 +197,39 @@ static const VMStateDescription vmstate_i440fx = {
.load_state_old = i440fx_load_old,
.post_load = i440fx_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, PCII440FXState),
+ VMSTATE_PCI_DEVICE(parent_obj, PCII440FXState),
VMSTATE_UINT8(smm_enabled, PCII440FXState),
VMSTATE_END_OF_LIST()
}
};
-static int i440fx_pcihost_initfn(SysBusDevice *dev)
+static void i440fx_pcihost_initfn(Object *obj)
{
- PCIHostState *s = PCI_HOST_BRIDGE(dev);
+ PCIHostState *s = PCI_HOST_BRIDGE(obj);
- memory_region_init_io(&s->conf_mem, OBJECT(dev), &pci_host_conf_le_ops, s,
+ memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s,
"pci-conf-idx", 4);
- sysbus_add_io(dev, 0xcf8, &s->conf_mem);
- sysbus_init_ioports(&s->busdev, 0xcf8, 4);
-
- memory_region_init_io(&s->data_mem, OBJECT(dev), &pci_host_data_le_ops, s,
+ memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s,
"pci-conf-data", 4);
- sysbus_add_io(dev, 0xcfc, &s->data_mem);
- sysbus_init_ioports(&s->busdev, 0xcfc, 4);
+}
- return 0;
+static void i440fx_pcihost_realize(DeviceState *dev, Error **errp)
+{
+ PCIHostState *s = PCI_HOST_BRIDGE(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ sysbus_add_io(sbd, 0xcf8, &s->conf_mem);
+ sysbus_init_ioports(sbd, 0xcf8, 4);
+
+ sysbus_add_io(sbd, 0xcfc, &s->data_mem);
+ sysbus_init_ioports(sbd, 0xcfc, 4);
}
static int i440fx_initfn(PCIDevice *dev)
{
PCII440FXState *d = I440FX_PCI_DEVICE(dev);
- d->dev.config[I440FX_SMRAM] = 0x02;
+ dev->config[I440FX_SMRAM] = 0x02;
cpu_smm_register(&i440fx_set_smm, d);
return 0;
@@ -305,9 +316,10 @@ static PCIBus *i440fx_common_init(const char *device_name,
*piix3_devfn = piix3->dev.devfn;
ram_size = ram_size / 8 / 1024 / 1024;
- if (ram_size > 255)
+ if (ram_size > 255) {
ram_size = 255;
- (*pi440fx_state)->dev.config[0x57]=ram_size;
+ }
+ d->config[0x57] = ram_size;
i440fx_update_memory_mappings(f);
@@ -640,11 +652,10 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
hc->root_bus_path = i440fx_pcihost_root_bus_path;
- k->init = i440fx_pcihost_initfn;
+ dc->realize = i440fx_pcihost_realize;
dc->fw_name = "pci";
dc->no_user = 1;
}
@@ -653,6 +664,7 @@ static const TypeInfo i440fx_pcihost_info = {
.name = "i440FX-pcihost",
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(I440FXState),
+ .instance_init = i440fx_pcihost_initfn,
.class_init = i440fx_pcihost_class_init,
};
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 8c3ee535ff..6b1b3b7ab1 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -34,33 +34,27 @@
* Q35 host
*/
-static int q35_host_init(SysBusDevice *dev)
+static void q35_host_realize(DeviceState *dev, Error **errp)
{
- PCIBus *b;
- PCIHostState *pci = FROM_SYSBUS(PCIHostState, dev);
- Q35PCIHost *s = Q35_HOST_DEVICE(&dev->qdev);
+ PCIHostState *pci = PCI_HOST_BRIDGE(dev);
+ Q35PCIHost *s = Q35_HOST_DEVICE(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- memory_region_init_io(&pci->conf_mem, OBJECT(pci), &pci_host_conf_le_ops, pci,
- "pci-conf-idx", 4);
- sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem);
- sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_ADDR, 4);
+ sysbus_add_io(sbd, MCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem);
+ sysbus_init_ioports(sbd, MCH_HOST_BRIDGE_CONFIG_ADDR, 4);
- memory_region_init_io(&pci->data_mem, OBJECT(pci), &pci_host_data_le_ops, pci,
- "pci-conf-data", 4);
- sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem);
- sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_DATA, 4);
+ sysbus_add_io(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem);
+ sysbus_init_ioports(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, 4);
- if (pcie_host_init(&s->host) < 0) {
- return -1;
+ if (pcie_host_init(PCIE_HOST_BRIDGE(s)) < 0) {
+ error_setg(errp, "failed to initialize pcie host");
+ return;
}
- b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0",
- s->mch.pci_address_space, s->mch.address_space_io,
- 0, TYPE_PCIE_BUS);
- s->host.pci.bus = b;
- qdev_set_parent_bus(DEVICE(&s->mch), BUS(b));
+ pci->bus = pci_bus_new(DEVICE(s), "pcie.0",
+ s->mch.pci_address_space, s->mch.address_space_io,
+ 0, TYPE_PCIE_BUS);
+ qdev_set_parent_bus(DEVICE(&s->mch), BUS(pci->bus));
qdev_init_nofail(DEVICE(&s->mch));
-
- return 0;
}
static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
@@ -71,7 +65,7 @@ static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
}
static Property mch_props[] = {
- DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
+ DEFINE_PROP_UINT64("MCFG", Q35PCIHost, parent_obj.base_addr,
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
DEFINE_PROP_END_OF_LIST(),
};
@@ -79,11 +73,10 @@ static Property mch_props[] = {
static void q35_host_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
hc->root_bus_path = q35_host_root_bus_path;
- k->init = q35_host_init;
+ dc->realize = q35_host_realize;
dc->props = mch_props;
dc->fw_name = "pci";
}
@@ -91,6 +84,12 @@ static void q35_host_class_init(ObjectClass *klass, void *data)
static void q35_host_initfn(Object *obj)
{
Q35PCIHost *s = Q35_HOST_DEVICE(obj);
+ PCIHostState *phb = PCI_HOST_BRIDGE(obj);
+
+ memory_region_init_io(&phb->conf_mem, obj, &pci_host_conf_le_ops, phb,
+ "pci-conf-idx", 4);
+ memory_region_init_io(&phb->data_mem, obj, &pci_host_data_le_ops, phb,
+ "pci-conf-data", 4);
object_initialize(&s->mch, TYPE_MCH_PCI_DEVICE);
object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL);
@@ -113,10 +112,9 @@ static const TypeInfo q35_host_info = {
/* PCIe MMCFG */
static void mch_update_pciexbar(MCHPCIState *mch)
{
- PCIDevice *pci_dev = &mch->d;
- BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
- DeviceState *qdev = bus->parent;
- Q35PCIHost *s = Q35_HOST_DEVICE(qdev);
+ PCIDevice *pci_dev = PCI_DEVICE(mch);
+ BusState *bus = qdev_get_parent_bus(DEVICE(mch));
+ PCIExpressHost *pehb = PCIE_HOST_BRIDGE(bus->parent);
uint64_t pciexbar;
int enable;
@@ -148,18 +146,19 @@ static void mch_update_pciexbar(MCHPCIState *mch)
break;
}
addr = pciexbar & addr_mask;
- pcie_host_mmcfg_update(&s->host, enable, addr, length);
+ pcie_host_mmcfg_update(pehb, enable, addr, length);
}
/* PAM */
static void mch_update_pam(MCHPCIState *mch)
{
+ PCIDevice *pd = PCI_DEVICE(mch);
int i;
memory_region_transaction_begin();
for (i = 0; i < 13; i++) {
pam_update(&mch->pam_regions[i], i,
- mch->d.config[MCH_HOST_BRIDGE_PAM0 + ((i + 1) / 2)]);
+ pd->config[MCH_HOST_BRIDGE_PAM0 + ((i + 1) / 2)]);
}
memory_region_transaction_commit();
}
@@ -167,8 +166,10 @@ static void mch_update_pam(MCHPCIState *mch)
/* SMRAM */
static void mch_update_smram(MCHPCIState *mch)
{
+ PCIDevice *pd = PCI_DEVICE(mch);
+
memory_region_transaction_begin();
- smram_update(&mch->smram_region, mch->d.config[MCH_HOST_BRDIGE_SMRAM],
+ smram_update(&mch->smram_region, pd->config[MCH_HOST_BRDIGE_SMRAM],
mch->smm_enabled);
memory_region_transaction_commit();
}
@@ -176,9 +177,10 @@ static void mch_update_smram(MCHPCIState *mch)
static void mch_set_smm(int smm, void *arg)
{
MCHPCIState *mch = arg;
+ PCIDevice *pd = PCI_DEVICE(mch);
memory_region_transaction_begin();
- smram_set_smm(&mch->smm_enabled, smm, mch->d.config[MCH_HOST_BRDIGE_SMRAM],
+ smram_set_smm(&mch->smm_enabled, smm, pd->config[MCH_HOST_BRDIGE_SMRAM],
&mch->smram_region);
memory_region_transaction_commit();
}
@@ -228,7 +230,7 @@ static const VMStateDescription vmstate_mch = {
.minimum_version_id_old = 1,
.post_load = mch_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(d, MCHPCIState),
+ VMSTATE_PCI_DEVICE(parent_obj, MCHPCIState),
VMSTATE_UINT8(smm_enabled, MCHPCIState),
VMSTATE_END_OF_LIST()
}
diff --git a/hw/pci/pci-hotplug-old.c b/hw/pci/pci-hotplug-old.c
index 8077289756..619fe473e8 100644
--- a/hw/pci/pci-hotplug-old.c
+++ b/hw/pci/pci-hotplug-old.c
@@ -127,7 +127,7 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
dinfo->bus = scsibus->busnr;
scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit,
- false, -1, NULL);
+ false, -1, NULL, NULL);
if (!scsidev) {
return -1;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index dcc85ef0af..81cf5a958c 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -378,6 +378,7 @@ int pci_bus_num(PCIBus *s)
static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
{
PCIDevice *s = container_of(pv, PCIDevice, config);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(s);
uint8_t *config;
int i;
@@ -395,6 +396,10 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
memcpy(s->config, config, size);
pci_update_mappings(s);
+ if (pc->is_bridge) {
+ PCIBridge *b = container_of(s, PCIBridge, dev);
+ pci_bridge_update_mappings(b);
+ }
memory_region_set_enabled(&s->bus_master_enable_region,
pci_get_word(s->config + PCI_COMMAND)
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index ecdeab0d58..02a396b01c 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -224,7 +224,7 @@ static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
g_free(w);
}
-static void pci_bridge_update_mappings(PCIBridge *br)
+void pci_bridge_update_mappings(PCIBridge *br)
{
PCIBridgeWindows *w = br->windows;
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index fe803480a7..7ef806ef7f 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -152,6 +152,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
CPUPPCState *env = NULL;
char *filename;
qemu_irq *pic, **openpic_irqs;
+ MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *unin_memory = g_new(MemoryRegion, 1);
MemoryRegion *unin2_memory = g_new(MemoryRegion, 1);
int linux_boot, i, j, k;
@@ -288,7 +289,9 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
}
/* Register 8 MB of ISA IO space */
- isa_mmio_init(0xf2000000, 0x00800000);
+ memory_region_init_alias(isa, NULL, "isa_mmio",
+ get_system_io(), 0, 0x00800000);
+ memory_region_add_subregion(get_system_memory(), 0xf2000000, isa);
/* UniN init: XXX should be a real device */
memory_region_init_io(unin_memory, NULL, &unin_ops, token, "unin", 0x1000);
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 8b8c6b93a5..42bb9d55c8 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -87,6 +87,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args)
int linux_boot, i;
MemoryRegion *ram = g_new(MemoryRegion, 1);
MemoryRegion *bios = g_new(MemoryRegion, 1);
+ MemoryRegion *isa = g_new(MemoryRegion, 1);
uint32_t kernel_base, initrd_base, cmdline_base = 0;
int32_t kernel_size, initrd_size;
PCIBus *pci_bus;
@@ -225,7 +226,9 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args)
}
/* Register 2 MB of ISA IO space */
- isa_mmio_init(0xfe000000, 0x00200000);
+ memory_region_init_alias(isa, NULL, "isa_mmio",
+ get_system_io(), 0, 0x00200000);
+ memory_region_add_subregion(sysmem, 0xfe000000, isa);
/* XXX: we register only 1 output pin for heathrow PIC */
heathrow_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 5b039abb38..369ab9e26e 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -164,6 +164,7 @@ static void bamboo_init(QEMUMachineInitArgs *args)
const char *initrd_filename = args->initrd_filename;
unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *ram_memories
= g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
@@ -225,7 +226,9 @@ static void bamboo_init(QEMUMachineInitArgs *args)
exit(1);
}
- isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
+ memory_region_init_alias(isa, NULL, "isa_mmio",
+ get_system_io(), 0, PPC440EP_PCI_IOLEN);
+ memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa);
if (serial_hds[0] != NULL) {
serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 19f2442482..7e04b1ac84 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -410,7 +410,7 @@ static const MemoryRegionOps PPC_prep_io_ops = {
.read = { PPC_prep_io_readb, PPC_prep_io_readw, PPC_prep_io_readl },
.write = { PPC_prep_io_writeb, PPC_prep_io_writew, PPC_prep_io_writel },
},
- .endianness = DEVICE_LITTLE_ENDIAN,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
#define NVRAM_SIZE 0x2000
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 318bc9d6ef..c880a757c8 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -440,43 +440,6 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
}
-static uint64_t spapr_io_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return cpu_inb(addr);
- case 2:
- return cpu_inw(addr);
- case 4:
- return cpu_inl(addr);
- }
- g_assert_not_reached();
-}
-
-static void spapr_io_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- switch (size) {
- case 1:
- cpu_outb(addr, data);
- return;
- case 2:
- cpu_outw(addr, data);
- return;
- case 4:
- cpu_outl(addr, data);
- return;
- }
- g_assert_not_reached();
-}
-
-static const MemoryRegionOps spapr_io_ops = {
- .endianness = DEVICE_LITTLE_ENDIAN,
- .read = spapr_io_read,
- .write = spapr_io_write
-};
-
/*
* MSI/MSIX memory region implementation.
* The handler handles both MSI and MSIX.
@@ -605,8 +568,8 @@ static int spapr_phb_init(SysBusDevice *s)
memory_region_add_subregion(get_system_io(), 0, &sphb->iospace);
sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
- memory_region_init_io(&sphb->iowindow, OBJECT(sphb), &spapr_io_ops, sphb,
- namebuf, SPAPR_PCI_IO_WIN_SIZE);
+ memory_region_init_alias(&sphb->iowindow, OBJECT(sphb), namebuf,
+ get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE);
memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
&sphb->iowindow);
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index 8f97c5a6e2..2ac21d4487 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -31,6 +31,9 @@
#define TYPE_AM53C974_DEVICE "am53c974"
+#define PCI_ESP(obj) \
+ OBJECT_CHECK(PCIESPState, (obj), TYPE_AM53C974_DEVICE)
+
#define DMA_CMD 0x0
#define DMA_STC 0x1
#define DMA_SPA 0x2
@@ -57,7 +60,10 @@
#define SBAC_STATUS 0x1000
typedef struct PCIESPState {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
MemoryRegion io;
uint32_t dma_regs[8];
uint32_t sbac;
@@ -257,7 +263,7 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
len = pci->dma_regs[DMA_WBC];
}
- pci_dma_rw(&pci->dev, addr, buf, len, dir);
+ pci_dma_rw(PCI_DEVICE(pci), addr, buf, len, dir);
/* update status registers */
pci->dma_regs[DMA_WBC] -= len;
@@ -288,7 +294,7 @@ static const MemoryRegionOps esp_pci_io_ops = {
static void esp_pci_hard_reset(DeviceState *dev)
{
- PCIESPState *pci = DO_UPCAST(PCIESPState, dev.qdev, dev);
+ PCIESPState *pci = PCI_ESP(dev);
esp_hard_reset(&pci->esp);
pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
| DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
@@ -306,7 +312,7 @@ static const VMStateDescription vmstate_esp_pci_scsi = {
.minimum_version_id = 0,
.minimum_version_id_old = 0,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PCIESPState),
+ VMSTATE_PCI_DEVICE(parent_obj, PCIESPState),
VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
VMSTATE_END_OF_LIST()
@@ -336,11 +342,13 @@ static const struct SCSIBusInfo esp_pci_scsi_info = {
static int esp_pci_scsi_init(PCIDevice *dev)
{
- PCIESPState *pci = DO_UPCAST(PCIESPState, dev, dev);
+ PCIESPState *pci = PCI_ESP(dev);
+ DeviceState *d = DEVICE(dev);
ESPState *s = &pci->esp;
uint8_t *pci_conf;
+ Error *err = NULL;
- pci_conf = pci->dev.config;
+ pci_conf = dev->config;
/* Interrupt pin A */
pci_conf[PCI_INTERRUPT_PIN] = 0x01;
@@ -352,19 +360,23 @@ static int esp_pci_scsi_init(PCIDevice *dev)
memory_region_init_io(&pci->io, OBJECT(pci), &esp_pci_io_ops, pci,
"esp-io", 0x80);
- pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
- s->irq = pci->dev.irq[0];
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
+ s->irq = dev->irq[0];
- scsi_bus_new(&s->bus, &dev->qdev, &esp_pci_scsi_info, NULL);
- if (!dev->qdev.hotplugged) {
- return scsi_bus_legacy_handle_cmdline(&s->bus);
+ scsi_bus_new(&s->bus, d, &esp_pci_scsi_info, NULL);
+ if (!d->hotplugged) {
+ scsi_bus_legacy_handle_cmdline(&s->bus, &err);
+ if (err != NULL) {
+ error_free(err);
+ return -1;
+ }
}
return 0;
}
static void esp_pci_scsi_uninit(PCIDevice *d)
{
- PCIESPState *pci = DO_UPCAST(PCIESPState, dev, d);
+ PCIESPState *pci = PCI_ESP(d);
memory_region_destroy(&pci->io);
}
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index c6166c5cc2..94639b8391 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -578,8 +578,14 @@ const VMStateDescription vmstate_esp = {
}
};
+#define TYPE_ESP "esp"
+#define ESP(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP)
+
typedef struct {
- SysBusDevice busdev;
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
MemoryRegion iomem;
uint32_t it_shift;
ESPState esp;
@@ -623,8 +629,8 @@ void esp_init(hwaddr espaddr, int it_shift,
SysBusESPState *sysbus;
ESPState *esp;
- dev = qdev_create(NULL, "esp");
- sysbus = DO_UPCAST(SysBusESPState, busdev.qdev, dev);
+ dev = qdev_create(NULL, TYPE_ESP);
+ sysbus = ESP(dev);
esp = &sysbus->esp;
esp->dma_memory_read = dma_memory_read;
esp->dma_memory_write = dma_memory_write;
@@ -652,8 +658,7 @@ static const struct SCSIBusInfo esp_scsi_info = {
static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
{
- DeviceState *d = opaque;
- SysBusESPState *sysbus = container_of(d, SysBusESPState, busdev.qdev);
+ SysBusESPState *sysbus = ESP(opaque);
ESPState *s = &sysbus->esp;
switch (irq) {
@@ -666,28 +671,34 @@ static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
}
}
-static int sysbus_esp_init(SysBusDevice *dev)
+static void sysbus_esp_realize(DeviceState *dev, Error **errp)
{
- SysBusESPState *sysbus = FROM_SYSBUS(SysBusESPState, dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ SysBusESPState *sysbus = ESP(dev);
ESPState *s = &sysbus->esp;
+ Error *err = NULL;
- sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(sbd, &s->irq);
assert(sysbus->it_shift != -1);
s->chip_id = TCHI_FAS100A;
memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops,
sysbus, "esp", ESP_REGS << sysbus->it_shift);
- sysbus_init_mmio(dev, &sysbus->iomem);
+ sysbus_init_mmio(sbd, &sysbus->iomem);
- qdev_init_gpio_in(&dev->qdev, sysbus_esp_gpio_demux, 2);
+ qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2);
- scsi_bus_new(&s->bus, &dev->qdev, &esp_scsi_info, NULL);
- return scsi_bus_legacy_handle_cmdline(&s->bus);
+ scsi_bus_new(&s->bus, dev, &esp_scsi_info, NULL);
+ scsi_bus_legacy_handle_cmdline(&s->bus, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
}
static void sysbus_esp_hard_reset(DeviceState *dev)
{
- SysBusESPState *sysbus = DO_UPCAST(SysBusESPState, busdev.qdev, dev);
+ SysBusESPState *sysbus = ESP(dev);
esp_hard_reset(&sysbus->esp);
}
@@ -705,15 +716,14 @@ static const VMStateDescription vmstate_sysbus_esp_scsi = {
static void sysbus_esp_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = sysbus_esp_init;
+ dc->realize = sysbus_esp_realize;
dc->reset = sysbus_esp_hard_reset;
dc->vmsd = &vmstate_sysbus_esp_scsi;
}
static const TypeInfo sysbus_esp_info = {
- .name = "esp",
+ .name = TYPE_ESP,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SysBusESPState),
.class_init = sysbus_esp_class_init,
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 2c17ae5f25..776e31abbe 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -184,7 +184,10 @@ typedef struct lsi_request {
} lsi_request;
typedef struct {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
MemoryRegion mmio_io;
MemoryRegion ram_io;
MemoryRegion io_io;
@@ -275,6 +278,11 @@ typedef struct {
uint32_t script_ram[2048];
} LSIState;
+#define TYPE_LSI53C895A "lsi53c895a"
+
+#define LSI53C895A(obj) \
+ OBJECT_CHECK(LSIState, (obj), TYPE_LSI53C895A)
+
static inline int lsi_irq_on_rsl(LSIState *s)
{
return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
@@ -382,7 +390,7 @@ static inline uint32_t read_dword(LSIState *s, uint32_t addr)
{
uint32_t buf;
- pci_dma_read(&s->dev, addr, &buf, 4);
+ pci_dma_read(PCI_DEVICE(s), addr, &buf, 4);
return cpu_to_le32(buf);
}
@@ -393,6 +401,7 @@ static void lsi_stop_script(LSIState *s)
static void lsi_update_irq(LSIState *s)
{
+ PCIDevice *d = PCI_DEVICE(s);
int level;
static int last_level;
lsi_request *p;
@@ -424,7 +433,7 @@ static void lsi_update_irq(LSIState *s)
level, s->dstat, s->sist1, s->sist0);
last_level = level;
}
- qemu_set_irq(s->dev.irq[0], level);
+ qemu_set_irq(d->irq[0], level);
if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
DPRINTF("Handled IRQs & disconnected, looking for pending "
@@ -520,6 +529,7 @@ static void lsi_bad_selection(LSIState *s, uint32_t id)
/* Initiate a SCSI layer data transfer. */
static void lsi_do_dma(LSIState *s, int out)
{
+ PCIDevice *pci_dev;
uint32_t count;
dma_addr_t addr;
SCSIDevice *dev;
@@ -531,6 +541,7 @@ static void lsi_do_dma(LSIState *s, int out)
return;
}
+ pci_dev = PCI_DEVICE(s);
dev = s->current->req->dev;
assert(dev);
@@ -556,9 +567,9 @@ static void lsi_do_dma(LSIState *s, int out)
}
/* ??? Set SFBR to first data byte. */
if (out) {
- pci_dma_read(&s->dev, addr, s->current->dma_buf, count);
+ pci_dma_read(pci_dev, addr, s->current->dma_buf, count);
} else {
- pci_dma_write(&s->dev, addr, s->current->dma_buf, count);
+ pci_dma_write(pci_dev, addr, s->current->dma_buf, count);
}
s->current->dma_len -= count;
if (s->current->dma_len == 0) {
@@ -653,7 +664,7 @@ static void lsi_request_free(LSIState *s, lsi_request *p)
static void lsi_request_cancelled(SCSIRequest *req)
{
- LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+ LSIState *s = LSI53C895A(req->bus->qbus.parent);
lsi_request *p = req->hba_private;
req->hba_private = NULL;
@@ -692,7 +703,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
/* Callback to indicate that the SCSI layer has completed a command. */
static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
{
- LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+ LSIState *s = LSI53C895A(req->bus->qbus.parent);
int out;
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
@@ -717,7 +728,7 @@ static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid
/* Callback to indicate that the SCSI layer has completed a transfer. */
static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
{
- LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+ LSIState *s = LSI53C895A(req->bus->qbus.parent);
int out;
assert(req->hba_private);
@@ -753,7 +764,7 @@ static void lsi_do_command(LSIState *s)
DPRINTF("Send command len=%d\n", s->dbc);
if (s->dbc > 16)
s->dbc = 16;
- pci_dma_read(&s->dev, s->dnad, buf, s->dbc);
+ pci_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc);
s->sfbr = buf[0];
s->command_complete = 0;
@@ -804,7 +815,7 @@ static void lsi_do_status(LSIState *s)
s->dbc = 1;
status = s->status;
s->sfbr = status;
- pci_dma_write(&s->dev, s->dnad, &status, 1);
+ pci_dma_write(PCI_DEVICE(s), s->dnad, &status, 1);
lsi_set_phase(s, PHASE_MI);
s->msg_action = 1;
lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
@@ -818,7 +829,7 @@ static void lsi_do_msgin(LSIState *s)
len = s->msg_len;
if (len > s->dbc)
len = s->dbc;
- pci_dma_write(&s->dev, s->dnad, s->msg, len);
+ pci_dma_write(PCI_DEVICE(s), s->dnad, s->msg, len);
/* Linux drivers rely on the last byte being in the SIDL. */
s->sidl = s->msg[len - 1];
s->msg_len -= len;
@@ -850,7 +861,7 @@ static void lsi_do_msgin(LSIState *s)
static uint8_t lsi_get_msgbyte(LSIState *s)
{
uint8_t data;
- pci_dma_read(&s->dev, s->dnad, &data, 1);
+ pci_dma_read(PCI_DEVICE(s), s->dnad, &data, 1);
s->dnad++;
s->dbc--;
return data;
@@ -996,14 +1007,15 @@ static inline int32_t sxt24(int32_t n)
#define LSI_BUF_SIZE 4096
static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
{
+ PCIDevice *d = PCI_DEVICE(s);
int n;
uint8_t buf[LSI_BUF_SIZE];
DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
while (count) {
n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
- pci_dma_read(&s->dev, src, buf, n);
- pci_dma_write(&s->dev, dest, buf, n);
+ pci_dma_read(d, src, buf, n);
+ pci_dma_write(d, dest, buf, n);
src += n;
dest += n;
count -= n;
@@ -1029,6 +1041,7 @@ static void lsi_wait_reselect(LSIState *s)
static void lsi_execute_script(LSIState *s)
{
+ PCIDevice *pci_dev = PCI_DEVICE(s);
uint32_t insn;
uint32_t addr, addr_high;
int opcode;
@@ -1071,7 +1084,7 @@ again:
/* 32-bit Table indirect */
offset = sxt24(addr);
- pci_dma_read(&s->dev, s->dsa + offset, buf, 8);
+ pci_dma_read(pci_dev, s->dsa + offset, buf, 8);
/* byte count is stored in bits 0:23 only */
s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
s->rbc = s->dbc;
@@ -1430,7 +1443,7 @@ again:
n = (insn & 7);
reg = (insn >> 16) & 0xff;
if (insn & (1 << 24)) {
- pci_dma_read(&s->dev, addr, data, n);
+ pci_dma_read(pci_dev, addr, data, n);
DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
addr, *(int *)data);
for (i = 0; i < n; i++) {
@@ -1441,7 +1454,7 @@ again:
for (i = 0; i < n; i++) {
data[i] = lsi_reg_readb(s, reg + i);
}
- pci_dma_write(&s->dev, addr, data, n);
+ pci_dma_write(pci_dev, addr, data, n);
}
}
}
@@ -1726,7 +1739,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
lsi_execute_script(s);
}
if (val & LSI_ISTAT0_SRST) {
- qdev_reset_all(&s->dev.qdev);
+ qdev_reset_all(DEVICE(s));
}
break;
case 0x16: /* MBOX0 */
@@ -1960,7 +1973,7 @@ static const MemoryRegionOps lsi_io_ops = {
static void lsi_scsi_reset(DeviceState *dev)
{
- LSIState *s = DO_UPCAST(LSIState, dev.qdev, dev);
+ LSIState *s = LSI53C895A(dev);
lsi_soft_reset(s);
}
@@ -1983,7 +1996,7 @@ static const VMStateDescription vmstate_lsi_scsi = {
.minimum_version_id_old = 0,
.pre_save = lsi_pre_save,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, LSIState),
+ VMSTATE_PCI_DEVICE(parent_obj, LSIState),
VMSTATE_INT32(carry, LSIState),
VMSTATE_INT32(status, LSIState),
@@ -2061,7 +2074,7 @@ static const VMStateDescription vmstate_lsi_scsi = {
static void lsi_scsi_uninit(PCIDevice *d)
{
- LSIState *s = DO_UPCAST(LSIState, dev, d);
+ LSIState *s = LSI53C895A(d);
memory_region_destroy(&s->mmio_io);
memory_region_destroy(&s->ram_io);
@@ -2080,10 +2093,12 @@ static const struct SCSIBusInfo lsi_scsi_info = {
static int lsi_scsi_init(PCIDevice *dev)
{
- LSIState *s = DO_UPCAST(LSIState, dev, dev);
+ LSIState *s = LSI53C895A(dev);
+ DeviceState *d = DEVICE(dev);
uint8_t *pci_conf;
+ Error *err = NULL;
- pci_conf = s->dev.config;
+ pci_conf = dev->config;
/* PCI latency timer = 255 */
pci_conf[PCI_LATENCY_TIMER] = 0xff;
@@ -2097,14 +2112,18 @@ static int lsi_scsi_init(PCIDevice *dev)
memory_region_init_io(&s->io_io, OBJECT(s), &lsi_io_ops, s,
"lsi-io", 256);
- pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
- pci_register_bar(&s->dev, 1, 0, &s->mmio_io);
- pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
+ pci_register_bar(dev, 1, 0, &s->mmio_io);
+ pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
QTAILQ_INIT(&s->queue);
- scsi_bus_new(&s->bus, &dev->qdev, &lsi_scsi_info, NULL);
- if (!dev->qdev.hotplugged) {
- return scsi_bus_legacy_handle_cmdline(&s->bus);
+ scsi_bus_new(&s->bus, d, &lsi_scsi_info, NULL);
+ if (!d->hotplugged) {
+ scsi_bus_legacy_handle_cmdline(&s->bus, &err);
+ if (err != NULL) {
+ error_free(err);
+ return -1;
+ }
}
return 0;
}
@@ -2125,7 +2144,7 @@ static void lsi_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo lsi_info = {
- .name = "lsi53c895a",
+ .name = TYPE_LSI53C895A,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(LSIState),
.class_init = lsi_class_init,
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 45d0c77c49..eb52164f6d 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -70,7 +70,10 @@ typedef struct MegasasCmd {
} MegasasCmd;
typedef struct MegasasState {
- PCIDevice dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
MemoryRegion mmio_io;
MemoryRegion port_io;
MemoryRegion queue_io;
@@ -108,6 +111,11 @@ typedef struct MegasasState {
SCSIBus bus;
} MegasasState;
+#define TYPE_MEGASAS "megasas"
+
+#define MEGASAS(obj) \
+ OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS)
+
#define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF
static bool megasas_intr_enabled(MegasasState *s)
@@ -232,7 +240,7 @@ static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl)
MEGASAS_MAX_SGE);
return iov_count;
}
- pci_dma_sglist_init(&cmd->qsg, &s->dev, iov_count);
+ pci_dma_sglist_init(&cmd->qsg, PCI_DEVICE(s), iov_count);
for (i = 0; i < iov_count; i++) {
dma_addr_t iov_pa, iov_size_p;
@@ -493,6 +501,7 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
static void megasas_complete_frame(MegasasState *s, uint64_t context)
{
+ PCIDevice *pci_dev = PCI_DEVICE(s);
int tail, queue_offset;
/* Decrement busy count */
@@ -521,12 +530,12 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
/* Notify HBA */
s->doorbell++;
if (s->doorbell == 1) {
- if (msix_enabled(&s->dev)) {
+ if (msix_enabled(pci_dev)) {
trace_megasas_msix_raise(0);
- msix_notify(&s->dev, 0);
+ msix_notify(pci_dev, 0);
} else {
trace_megasas_irq_raise();
- qemu_irq_raise(s->dev.irq[0]);
+ qemu_irq_raise(pci_dev->irq[0]);
}
}
} else {
@@ -628,7 +637,7 @@ static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd)
}
iov_pa = megasas_sgl_get_addr(cmd, &cmd->frame->dcmd.sgl);
iov_size = megasas_sgl_get_len(cmd, &cmd->frame->dcmd.sgl);
- pci_dma_sglist_init(&cmd->qsg, &s->dev, 1);
+ pci_dma_sglist_init(&cmd->qsg, PCI_DEVICE(s), 1);
qemu_sglist_add(&cmd->qsg, iov_pa, iov_size);
cmd->iov_size = iov_size;
return cmd->iov_size;
@@ -655,6 +664,7 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size)
static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
{
+ PCIDevice *pci_dev = PCI_DEVICE(s);
struct mfi_ctrl_info info;
size_t dcmd_size = sizeof(info);
BusChild *kid;
@@ -705,11 +715,11 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
memcpy(info.image_component[0].build_date, __DATE__, 11);
memcpy(info.image_component[0].build_time, __TIME__, 8);
info.image_component_count = 1;
- if (s->dev.has_rom) {
+ if (pci_dev->has_rom) {
uint8_t biosver[32];
uint8_t *ptr;
- ptr = memory_region_get_ram_ptr(&s->dev.rom);
+ ptr = memory_region_get_ram_ptr(&pci_dev->rom);
memcpy(biosver, ptr + 0x41, 31);
memcpy(info.image_component[1].name, "BIOS", 4);
memcpy(info.image_component[1].version, biosver,
@@ -1900,6 +1910,7 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
MegasasState *s = opaque;
+ PCIDevice *pci_dev = PCI_DEVICE(s);
uint64_t frame_addr;
uint32_t frame_count;
int i;
@@ -1923,9 +1934,9 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
break;
case MFI_OMSK:
s->intr_mask = val;
- if (!megasas_intr_enabled(s) && !msix_enabled(&s->dev)) {
+ if (!megasas_intr_enabled(s) && !msix_enabled(pci_dev)) {
trace_megasas_irq_lower();
- qemu_irq_lower(s->dev.irq[0]);
+ qemu_irq_lower(pci_dev->irq[0]);
}
if (megasas_intr_enabled(s)) {
trace_megasas_intr_enabled();
@@ -1939,9 +1950,9 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
/* Update reply queue pointer */
trace_megasas_qf_update(s->reply_queue_head, s->busy);
stl_le_phys(s->producer_pa, s->reply_queue_head);
- if (!msix_enabled(&s->dev)) {
+ if (!msix_enabled(pci_dev)) {
trace_megasas_irq_lower();
- qemu_irq_lower(s->dev.irq[0]);
+ qemu_irq_lower(pci_dev->irq[0]);
}
}
break;
@@ -2039,7 +2050,7 @@ static void megasas_soft_reset(MegasasState *s)
static void megasas_scsi_reset(DeviceState *dev)
{
- MegasasState *s = DO_UPCAST(MegasasState, dev.qdev, dev);
+ MegasasState *s = MEGASAS(dev);
megasas_soft_reset(s);
}
@@ -2050,7 +2061,7 @@ static const VMStateDescription vmstate_megasas = {
.minimum_version_id = 0,
.minimum_version_id_old = 0,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, MegasasState),
+ VMSTATE_PCI_DEVICE(parent_obj, MegasasState),
VMSTATE_INT32(fw_state, MegasasState),
VMSTATE_INT32(intr_mask, MegasasState),
@@ -2064,10 +2075,10 @@ static const VMStateDescription vmstate_megasas = {
static void megasas_scsi_uninit(PCIDevice *d)
{
- MegasasState *s = DO_UPCAST(MegasasState, dev, d);
+ MegasasState *s = MEGASAS(d);
#ifdef USE_MSIX
- msix_uninit(&s->dev, &s->mmio_io);
+ msix_uninit(d, &s->mmio_io);
#endif
memory_region_destroy(&s->mmio_io);
memory_region_destroy(&s->port_io);
@@ -2087,11 +2098,13 @@ static const struct SCSIBusInfo megasas_scsi_info = {
static int megasas_scsi_init(PCIDevice *dev)
{
- MegasasState *s = DO_UPCAST(MegasasState, dev, dev);
+ DeviceState *d = DEVICE(dev);
+ MegasasState *s = MEGASAS(dev);
uint8_t *pci_conf;
int i, bar_type;
+ Error *err = NULL;
- pci_conf = s->dev.config;
+ pci_conf = dev->config;
/* PCI latency timer = 0 */
pci_conf[PCI_LATENCY_TIMER] = 0;
@@ -2108,7 +2121,7 @@ static int megasas_scsi_init(PCIDevice *dev)
#ifdef USE_MSIX
/* MSI-X support is currently broken */
if (megasas_use_msix(s) &&
- msix_init(&s->dev, 15, &s->mmio_io, 0, 0x2000)) {
+ msix_init(dev, 15, &s->mmio_io, 0, 0x2000)) {
s->flags &= ~MEGASAS_MASK_USE_MSIX;
}
#else
@@ -2116,12 +2129,12 @@ static int megasas_scsi_init(PCIDevice *dev)
#endif
bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
- pci_register_bar(&s->dev, 0, bar_type, &s->mmio_io);
- pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
- pci_register_bar(&s->dev, 3, bar_type, &s->queue_io);
+ pci_register_bar(dev, 0, bar_type, &s->mmio_io);
+ pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
+ pci_register_bar(dev, 3, bar_type, &s->queue_io);
if (megasas_use_msix(s)) {
- msix_vector_use(&s->dev, 0);
+ msix_vector_use(dev, 0);
}
if (!s->sas_addr) {
@@ -2158,8 +2171,14 @@ static int megasas_scsi_init(PCIDevice *dev)
s->frames[i].state = s;
}
- scsi_bus_new(&s->bus, &dev->qdev, &megasas_scsi_info, NULL);
- scsi_bus_legacy_handle_cmdline(&s->bus);
+ scsi_bus_new(&s->bus, DEVICE(dev), &megasas_scsi_info, NULL);
+ if (!d->hotplugged) {
+ scsi_bus_legacy_handle_cmdline(&s->bus, &err);
+ if (err != NULL) {
+ error_free(err);
+ return -1;
+ }
+ }
return 0;
}
@@ -2198,7 +2217,7 @@ static void megasas_class_init(ObjectClass *oc, void *data)
}
static const TypeInfo megasas_info = {
- .name = "megasas",
+ .name = TYPE_MEGASAS,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(MegasasState),
.class_init = megasas_class_init,
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index a92b7c1de4..b5a863aa5c 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -209,10 +209,11 @@ static int scsi_qdev_exit(DeviceState *qdev)
/* handle legacy '-drive if=scsi,...' cmd line args */
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
int unit, bool removable, int bootindex,
- const char *serial)
+ const char *serial, Error **errp)
{
const char *driver;
DeviceState *dev;
+ Error *err = NULL;
driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
dev = qdev_create(&bus->qbus, driver);
@@ -227,19 +228,25 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
qdev_prop_set_string(dev, "serial", serial);
}
if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
+ error_setg(errp, "Setting drive property failed");
qdev_free(dev);
return NULL;
}
- if (qdev_init(dev) < 0)
+ object_property_set_bool(OBJECT(dev), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ qdev_free(dev);
return NULL;
+ }
return SCSI_DEVICE(dev);
}
-int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
+void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, Error **errp)
{
Location loc;
DriveInfo *dinfo;
- int res = 0, unit;
+ int unit;
+ Error *err = NULL;
loc_push_none(&loc);
for (unit = 0; unit <= bus->info->max_target; unit++) {
@@ -248,13 +255,14 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
continue;
}
qemu_opts_loc_restore(dinfo->opts);
- if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1, NULL)) {
- res = -1;
+ scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1, NULL,
+ &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
break;
}
}
loc_pop(&loc);
- return res;
}
static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf)
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index e8978bfef1..55b44b9910 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -912,12 +912,17 @@ static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
static int spapr_vscsi_init(VIOsPAPRDevice *dev)
{
VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
+ Error *err = NULL;
dev->crq.SendFunc = vscsi_do_crq;
scsi_bus_new(&s->bus, &dev->qdev, &vscsi_scsi_info, NULL);
if (!dev->qdev.hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus);
+ scsi_bus_legacy_handle_cmdline(&s->bus, &err);
+ if (err != NULL) {
+ error_free(err);
+ return -1;
+ }
}
return 0;
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 712f0ade22..42cb73bb4e 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -619,6 +619,7 @@ static int virtio_scsi_device_init(VirtIODevice *vdev)
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
static int virtio_scsi_id;
+ Error *err = NULL;
int ret;
ret = virtio_scsi_common_init(vs);
@@ -629,7 +630,11 @@ static int virtio_scsi_device_init(VirtIODevice *vdev)
scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info, vdev->bus_name);
if (!qdev->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus);
+ scsi_bus_legacy_handle_cmdline(&s->bus, &err);
+ if (err != NULL) {
+ error_free(err);
+ return -1;
+ }
}
register_savevm(qdev, "virtio-scsi", virtio_scsi_id++, 1,
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index 97d3aa3e6f..e1074e1d8d 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -1136,7 +1136,7 @@ pvscsi_post_load(void *opaque, int version_id)
}
static const VMStateDescription vmstate_pvscsi = {
- .name = TYPE_PVSCSI,
+ .name = "pvscsi",
.version_id = 0,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
@@ -1201,7 +1201,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo pvscsi_info = {
- .name = "pvscsi",
+ .name = TYPE_PVSCSI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PVSCSIState),
.class_init = pvscsi_class_init,
diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c
index c33a72f80f..e81176a11e 100644
--- a/hw/sh4/sh_pci.c
+++ b/hw/sh4/sh_pci.c
@@ -28,9 +28,14 @@
#include "qemu/bswap.h"
#include "exec/address-spaces.h"
+#define TYPE_SH_PCI_HOST_BRIDGE "sh_pci"
+
+#define SH_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(SHPCIState, (obj), TYPE_SH_PCI_HOST_BRIDGE)
+
typedef struct SHPCIState {
- SysBusDevice busdev;
- PCIBus *bus;
+ PCIHostState parent_obj;
+
PCIDevice *dev;
qemu_irq irq[4];
MemoryRegion memconfig_p4;
@@ -45,6 +50,8 @@ static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val,
unsigned size)
{
SHPCIState *pcic = p;
+ PCIHostState *phb = PCI_HOST_BRIDGE(pcic);
+
switch(addr) {
case 0 ... 0xfc:
cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val);
@@ -64,7 +71,7 @@ static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val,
}
break;
case 0x220:
- pci_data_write(pcic->bus, pcic->par, val, 4);
+ pci_data_write(phb->bus, pcic->par, val, 4);
break;
}
}
@@ -73,6 +80,8 @@ static uint64_t sh_pci_reg_read (void *p, hwaddr addr,
unsigned size)
{
SHPCIState *pcic = p;
+ PCIHostState *phb = PCI_HOST_BRIDGE(pcic);
+
switch(addr) {
case 0 ... 0xfc:
return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
@@ -83,7 +92,7 @@ static uint64_t sh_pci_reg_read (void *p, hwaddr addr,
case 0x1c8:
return pcic->iobr;
case 0x220:
- return pci_data_read(pcic->bus, pcic->par, 4);
+ return pci_data_read(phb->bus, pcic->par, 4);
}
return 0;
}
@@ -112,30 +121,33 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level)
static int sh_pci_device_init(SysBusDevice *dev)
{
+ PCIHostState *phb;
SHPCIState *s;
int i;
- s = FROM_SYSBUS(SHPCIState, dev);
+ s = SH_PCI_HOST_BRIDGE(dev);
+ phb = PCI_HOST_BRIDGE(s);
for (i = 0; i < 4; i++) {
sysbus_init_irq(dev, &s->irq[i]);
}
- s->bus = pci_register_bus(&s->busdev.qdev, "pci",
- sh_pci_set_irq, sh_pci_map_irq,
- s->irq,
- get_system_memory(),
- get_system_io(),
- PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
+ phb->bus = pci_register_bus(DEVICE(dev), "pci",
+ sh_pci_set_irq, sh_pci_map_irq,
+ s->irq,
+ get_system_memory(),
+ get_system_io(),
+ PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
memory_region_init_io(&s->memconfig_p4, OBJECT(s), &sh_pci_reg_ops, s,
"sh_pci", 0x224);
memory_region_init_alias(&s->memconfig_a7, OBJECT(s), "sh_pci.2",
&s->memconfig_p4, 0, 0x224);
- isa_mmio_setup(&s->isa, 0x40000);
+ memory_region_init_alias(&s->isa, OBJECT(s), "sh_pci.isa",
+ get_system_io(), 0, 0x40000);
sysbus_init_mmio(dev, &s->memconfig_p4);
sysbus_init_mmio(dev, &s->memconfig_a7);
s->iobr = 0xfe240000;
memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa);
- s->dev = pci_create_simple(s->bus, PCI_DEVFN(0, 0), "sh_pci_host");
+ s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host");
return 0;
}
@@ -171,8 +183,8 @@ static void sh_pci_device_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo sh_pci_device_info = {
- .name = "sh_pci",
- .parent = TYPE_SYS_BUS_DEVICE,
+ .name = TYPE_SH_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(SHPCIState),
.class_init = sh_pci_device_class_init,
};
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 564c1959ee..34a5e7331c 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -605,9 +605,11 @@ pci_ebus_init1(PCIDevice *pci_dev)
pci_dev->config[0x09] = 0x00; // programming i/f
pci_dev->config[0x0D] = 0x0a; // latency_timer
- isa_mmio_setup(&s->bar0, 0x1000000);
+ memory_region_init_alias(&s->bar0, OBJECT(s), "bar0", get_system_io(),
+ 0, 0x1000000);
pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
- isa_mmio_setup(&s->bar1, 0x800000);
+ memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
+ 0, 0x800000);
pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
return 0;
}
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 90bd5846b9..648b38362d 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -42,6 +42,9 @@
#define HPET_MSI_SUPPORT 0
+#define TYPE_HPET "hpet"
+#define HPET(obj) OBJECT_CHECK(HPETState, (obj), TYPE_HPET)
+
struct HPETState;
typedef struct HPETTimer { /* timers */
uint8_t tn; /*timer number*/
@@ -59,7 +62,10 @@ typedef struct HPETTimer { /* timers */
} HPETTimer;
typedef struct HPETState {
- SysBusDevice busdev;
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
MemoryRegion iomem;
uint64_t hpet_offset;
qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
@@ -634,7 +640,8 @@ static const MemoryRegionOps hpet_ram_ops = {
static void hpet_reset(DeviceState *d)
{
- HPETState *s = FROM_SYSBUS(HPETState, SYS_BUS_DEVICE(d));
+ HPETState *s = HPET(d);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(d);
int i;
for (i = 0; i < s->num_timers; i++) {
@@ -657,7 +664,7 @@ static void hpet_reset(DeviceState *d)
s->hpet_offset = 0ULL;
s->config = 0ULL;
hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
- hpet_cfg.hpet[s->hpet_id].address = SYS_BUS_DEVICE(d)->mmio[0].addr;
+ hpet_cfg.hpet[s->hpet_id].address = sbd->mmio[0].addr;
/* to document that the RTC lowers its output on reset as well */
s->rtc_irq_level = 0;
@@ -665,7 +672,7 @@ static void hpet_reset(DeviceState *d)
static void hpet_handle_legacy_irq(void *opaque, int n, int level)
{
- HPETState *s = FROM_SYSBUS(HPETState, opaque);
+ HPETState *s = HPET(opaque);
if (n == HPET_LEGACY_PIT_INT) {
if (!hpet_in_legacy_mode(s)) {
@@ -679,9 +686,20 @@ static void hpet_handle_legacy_irq(void *opaque, int n, int level)
}
}
-static int hpet_init(SysBusDevice *dev)
+static void hpet_init(Object *obj)
{
- HPETState *s = FROM_SYSBUS(HPETState, dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ HPETState *s = HPET(obj);
+
+ /* HPET Area */
+ memory_region_init_io(&s->iomem, obj, &hpet_ram_ops, s, "hpet", 0x400);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void hpet_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ HPETState *s = HPET(dev);
int i;
HPETTimer *timer;
@@ -691,14 +709,14 @@ static int hpet_init(SysBusDevice *dev)
}
if (hpet_cfg.count == 8) {
- fprintf(stderr, "Only 8 instances of HPET is allowed\n");
- return -1;
+ error_setg(errp, "Only 8 instances of HPET is allowed");
+ return;
}
s->hpet_id = hpet_cfg.count++;
for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
- sysbus_init_irq(dev, &s->irqs[i]);
+ sysbus_init_irq(sbd, &s->irqs[i]);
}
if (s->num_timers < HPET_MIN_TIMERS) {
@@ -718,13 +736,8 @@ static int hpet_init(SysBusDevice *dev)
s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
s->capability |= ((HPET_CLK_PERIOD) << 32);
- qdev_init_gpio_in(&dev->qdev, hpet_handle_legacy_irq, 2);
- qdev_init_gpio_out(&dev->qdev, &s->pit_enabled, 1);
-
- /* HPET Area */
- memory_region_init_io(&s->iomem, OBJECT(s), &hpet_ram_ops, s, "hpet", 0x400);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
+ qdev_init_gpio_in(dev, hpet_handle_legacy_irq, 2);
+ qdev_init_gpio_out(dev, &s->pit_enabled, 1);
}
static Property hpet_device_properties[] = {
@@ -736,9 +749,8 @@ static Property hpet_device_properties[] = {
static void hpet_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = hpet_init;
+ dc->realize = hpet_realize;
dc->no_user = 1;
dc->reset = hpet_reset;
dc->vmsd = &vmstate_hpet;
@@ -746,9 +758,10 @@ static void hpet_device_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo hpet_device_info = {
- .name = "hpet",
+ .name = TYPE_HPET,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(HPETState),
+ .instance_init = hpet_init,
.class_init = hpet_device_class_init,
};
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index e24e0c4916..117dc7bcbb 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -370,7 +370,7 @@ static const MemoryRegionOps imx_epit_ops = {
};
static const VMStateDescription vmstate_imx_timer_epit = {
- .name = TYPE_IMX_EPIT,
+ .name = "imx.epit",
.version_id = 2,
.minimum_version_id = 2,
.minimum_version_id_old = 2,
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 97fbebbe80..87db0e195c 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -142,7 +142,7 @@ typedef struct {
} IMXGPTState;
static const VMStateDescription vmstate_imx_timer_gpt = {
- .name = TYPE_IMX_GPT,
+ .name = "imx.gpt",
.version_id = 3,
.minimum_version_id = 3,
.minimum_version_id_old = 3,
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 01c7e6f20d..5f01ff1e16 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -364,7 +364,7 @@ static int passthru_exitfn(CCIDCardState *base)
}
static VMStateDescription passthru_vmstate = {
- .name = PASSTHRU_DEV_NAME,
+ .name = "ccid-card-passthru",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 125cc2c221..b33eb25b39 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1397,7 +1397,7 @@ static VMStateDescription usb_device_vmstate = {
};
static VMStateDescription ccid_vmstate = {
- .name = CCID_DEV_NAME,
+ .name = "usb-ccid",
.version_id = 1,
.minimum_version_id = 1,
.post_load = ccid_post_load,
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index fe914ab005..1954811ec4 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -595,6 +595,7 @@ static int usb_msd_initfn_storage(USBDevice *dev)
MSDState *s = DO_UPCAST(MSDState, dev, dev);
BlockDriverState *bs = s->conf.bs;
SCSIDevice *scsi_dev;
+ Error *err = NULL;
if (!bs) {
error_report("drive property not set");
@@ -619,7 +620,8 @@ static int usb_msd_initfn_storage(USBDevice *dev)
usb_desc_init(dev);
scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage, NULL);
scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
- s->conf.bootindex, dev->serial);
+ s->conf.bootindex, dev->serial,
+ &err);
if (!scsi_dev) {
return -1;
}
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index a096ecf214..2bab8ffb75 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -1843,51 +1843,61 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
return 0;
}
+#define TYPE_PCI_OHCI "pci-ohci"
+#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI)
+
typedef struct {
- PCIDevice pci_dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
OHCIState state;
char *masterbus;
uint32_t num_ports;
uint32_t firstport;
} OHCIPCIState;
-static int usb_ohci_initfn_pci(struct PCIDevice *dev)
+static int usb_ohci_initfn_pci(PCIDevice *dev)
{
- OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
+ OHCIPCIState *ohci = PCI_OHCI(dev);
- ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */
- ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+ dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */
+ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
- if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0,
+ if (usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0,
ohci->masterbus, ohci->firstport,
pci_get_address_space(dev)) != 0) {
return -1;
}
- ohci->state.irq = ohci->pci_dev.irq[0];
+ ohci->state.irq = dev->irq[0];
- /* TODO: avoid cast below by using dev */
- pci_register_bar(&ohci->pci_dev, 0, 0, &ohci->state.mem);
+ pci_register_bar(dev, 0, 0, &ohci->state.mem);
return 0;
}
+#define TYPE_SYSBUS_OHCI "sysbus-ohci"
+#define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI)
+
typedef struct {
- SysBusDevice busdev;
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
OHCIState ohci;
uint32_t num_ports;
dma_addr_t dma_offset;
} OHCISysBusState;
-static int ohci_init_pxa(SysBusDevice *dev)
+static void ohci_realize_pxa(DeviceState *dev, Error **errp)
{
- OHCISysBusState *s = FROM_SYSBUS(OHCISysBusState, dev);
+ OHCISysBusState *s = SYSBUS_OHCI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
/* Cannot fail as we pass NULL for masterbus */
- usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0,
+ usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, NULL, 0,
&address_space_memory);
- sysbus_init_irq(dev, &s->ohci.irq);
- sysbus_init_mmio(dev, &s->ohci.mem);
-
- return 0;
+ sysbus_init_irq(sbd, &s->ohci.irq);
+ sysbus_init_mmio(sbd, &s->ohci.mem);
}
static Property ohci_pci_properties[] = {
@@ -1912,7 +1922,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ohci_pci_info = {
- .name = "pci-ohci",
+ .name = TYPE_PCI_OHCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(OHCIPCIState),
.class_init = ohci_pci_class_init,
@@ -1927,15 +1937,14 @@ static Property ohci_sysbus_properties[] = {
static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
- sbc->init = ohci_init_pxa;
+ dc->realize = ohci_realize_pxa;
dc->desc = "OHCI USB Controller";
dc->props = ohci_sysbus_properties;
}
static const TypeInfo ohci_sysbus_info = {
- .name = "sysbus-ohci",
+ .name = TYPE_SYSBUS_OHCI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(OHCISysBusState),
.class_init = ohci_sysbus_class_init,
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index d7a54fd53f..9ba3e3e86d 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -443,7 +443,10 @@ typedef struct XHCIInterrupter {
} XHCIInterrupter;
struct XHCIState {
- PCIDevice pci_dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
USBBus bus;
qemu_irq irq;
MemoryRegion mem;
@@ -482,6 +485,11 @@ struct XHCIState {
XHCIRing cmd_ring;
};
+#define TYPE_XHCI "nec-usb-xhci"
+
+#define XHCI(obj) \
+ OBJECT_CHECK(XHCIState, (obj), TYPE_XHCI)
+
typedef struct XHCIEvRingSeg {
uint32_t addr_low;
uint32_t addr_high;
@@ -654,7 +662,7 @@ static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr,
assert((len % sizeof(uint32_t)) == 0);
- pci_dma_read(&xhci->pci_dev, addr, buf, len);
+ pci_dma_read(PCI_DEVICE(xhci), addr, buf, len);
for (i = 0; i < (len / sizeof(uint32_t)); i++) {
buf[i] = le32_to_cpu(buf[i]);
@@ -672,7 +680,7 @@ static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr,
for (i = 0; i < (len / sizeof(uint32_t)); i++) {
tmp[i] = cpu_to_le32(buf[i]);
}
- pci_dma_write(&xhci->pci_dev, addr, tmp, len);
+ pci_dma_write(PCI_DEVICE(xhci), addr, tmp, len);
}
static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
@@ -699,10 +707,11 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
static void xhci_intx_update(XHCIState *xhci)
{
+ PCIDevice *pci_dev = PCI_DEVICE(xhci);
int level = 0;
- if (msix_enabled(&xhci->pci_dev) ||
- msi_enabled(&xhci->pci_dev)) {
+ if (msix_enabled(pci_dev) ||
+ msi_enabled(pci_dev)) {
return;
}
@@ -718,9 +727,10 @@ static void xhci_intx_update(XHCIState *xhci)
static void xhci_msix_update(XHCIState *xhci, int v)
{
+ PCIDevice *pci_dev = PCI_DEVICE(xhci);
bool enabled;
- if (!msix_enabled(&xhci->pci_dev)) {
+ if (!msix_enabled(pci_dev)) {
return;
}
@@ -731,17 +741,19 @@ static void xhci_msix_update(XHCIState *xhci, int v)
if (enabled) {
trace_usb_xhci_irq_msix_use(v);
- msix_vector_use(&xhci->pci_dev, v);
+ msix_vector_use(pci_dev, v);
xhci->intr[v].msix_used = true;
} else {
trace_usb_xhci_irq_msix_unuse(v);
- msix_vector_unuse(&xhci->pci_dev, v);
+ msix_vector_unuse(pci_dev, v);
xhci->intr[v].msix_used = false;
}
}
static void xhci_intr_raise(XHCIState *xhci, int v)
{
+ PCIDevice *pci_dev = PCI_DEVICE(xhci);
+
xhci->intr[v].erdp_low |= ERDP_EHB;
xhci->intr[v].iman |= IMAN_IP;
xhci->usbsts |= USBSTS_EINT;
@@ -754,15 +766,15 @@ static void xhci_intr_raise(XHCIState *xhci, int v)
return;
}
- if (msix_enabled(&xhci->pci_dev)) {
+ if (msix_enabled(pci_dev)) {
trace_usb_xhci_irq_msix(v);
- msix_notify(&xhci->pci_dev, v);
+ msix_notify(pci_dev, v);
return;
}
- if (msi_enabled(&xhci->pci_dev)) {
+ if (msi_enabled(pci_dev)) {
trace_usb_xhci_irq_msi(v);
- msi_notify(&xhci->pci_dev, v);
+ msi_notify(pci_dev, v);
return;
}
@@ -785,6 +797,7 @@ static void xhci_die(XHCIState *xhci)
static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
{
+ PCIDevice *pci_dev = PCI_DEVICE(xhci);
XHCIInterrupter *intr = &xhci->intr[v];
XHCITRB ev_trb;
dma_addr_t addr;
@@ -803,7 +816,7 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
ev_trb.status, ev_trb.control);
addr = intr->er_start + TRB_SIZE*intr->er_ep_idx;
- pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE);
+ pci_dma_write(pci_dev, addr, &ev_trb, TRB_SIZE);
intr->er_ep_idx++;
if (intr->er_ep_idx >= intr->er_size) {
@@ -950,9 +963,11 @@ static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
dma_addr_t *addr)
{
+ PCIDevice *pci_dev = PCI_DEVICE(xhci);
+
while (1) {
TRBType type;
- pci_dma_read(&xhci->pci_dev, ring->dequeue, trb, TRB_SIZE);
+ pci_dma_read(pci_dev, ring->dequeue, trb, TRB_SIZE);
trb->addr = ring->dequeue;
trb->ccs = ring->ccs;
le64_to_cpus(&trb->parameter);
@@ -985,6 +1000,7 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
{
+ PCIDevice *pci_dev = PCI_DEVICE(xhci);
XHCITRB trb;
int length = 0;
dma_addr_t dequeue = ring->dequeue;
@@ -994,7 +1010,7 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
while (1) {
TRBType type;
- pci_dma_read(&xhci->pci_dev, dequeue, &trb, TRB_SIZE);
+ pci_dma_read(pci_dev, dequeue, &trb, TRB_SIZE);
le64_to_cpus(&trb.parameter);
le32_to_cpus(&trb.status);
le32_to_cpus(&trb.control);
@@ -1046,7 +1062,7 @@ static void xhci_er_reset(XHCIState *xhci, int v)
return;
}
dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high);
- pci_dma_read(&xhci->pci_dev, erstba, &seg, sizeof(seg));
+ pci_dma_read(PCI_DEVICE(xhci), erstba, &seg, sizeof(seg));
le32_to_cpus(&seg.addr_low);
le32_to_cpus(&seg.addr_high);
le32_to_cpus(&seg.size);
@@ -1521,7 +1537,7 @@ static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer)
int i;
xfer->int_req = false;
- pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count);
+ pci_dma_sglist_init(&xfer->sgl, PCI_DEVICE(xhci), xfer->trb_count);
for (i = 0; i < xfer->trb_count; i++) {
XHCITRB *trb = &xfer->trbs[i];
dma_addr_t addr;
@@ -2106,7 +2122,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
assert(slotid >= 1 && slotid <= xhci->numslots);
dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
- poctx = ldq_le_pci_dma(&xhci->pci_dev, dcbaap + 8*slotid);
+ poctx = ldq_le_pci_dma(PCI_DEVICE(xhci), dcbaap + 8 * slotid);
ictx = xhci_mask64(pictx);
octx = xhci_mask64(poctx);
@@ -2427,7 +2443,7 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
/* TODO: actually implement real values here */
bw_ctx[0] = 0;
memset(&bw_ctx[1], 80, xhci->numports); /* 80% */
- pci_dma_write(&xhci->pci_dev, ctx, bw_ctx, sizeof(bw_ctx));
+ pci_dma_write(PCI_DEVICE(xhci), ctx, bw_ctx, sizeof(bw_ctx));
return CC_SUCCESS;
}
@@ -2450,11 +2466,12 @@ static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo)
static void xhci_via_challenge(XHCIState *xhci, uint64_t addr)
{
+ PCIDevice *pci_dev = PCI_DEVICE(xhci);
uint32_t buf[8];
uint32_t obuf[8];
dma_addr_t paddr = xhci_mask64(addr);
- pci_dma_read(&xhci->pci_dev, paddr, &buf, 32);
+ pci_dma_read(pci_dev, paddr, &buf, 32);
memcpy(obuf, buf, sizeof(obuf));
@@ -2470,7 +2487,7 @@ static void xhci_via_challenge(XHCIState *xhci, uint64_t addr)
obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593;
}
- pci_dma_write(&xhci->pci_dev, paddr, &obuf, 32);
+ pci_dma_write(pci_dev, paddr, &obuf, 32);
}
static void xhci_process_commands(XHCIState *xhci)
@@ -2681,7 +2698,7 @@ static void xhci_port_reset(XHCIPort *port)
static void xhci_reset(DeviceState *dev)
{
- XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev.qdev, dev);
+ XHCIState *xhci = XHCI(dev);
int i;
trace_usb_xhci_reset();
@@ -2926,6 +2943,7 @@ static void xhci_oper_write(void *ptr, hwaddr reg,
uint64_t val, unsigned size)
{
XHCIState *xhci = ptr;
+ DeviceState *d = DEVICE(ptr);
trace_usb_xhci_oper_write(reg, val);
@@ -2939,7 +2957,7 @@ static void xhci_oper_write(void *ptr, hwaddr reg,
xhci->usbcmd = val & 0xc0f;
xhci_mfwrap_update(xhci);
if (val & USBCMD_HCRST) {
- xhci_reset(&xhci->pci_dev.qdev);
+ xhci_reset(d);
}
xhci_intx_update(xhci);
break;
@@ -3265,8 +3283,9 @@ static USBBusOps xhci_bus_ops = {
.wakeup_endpoint = xhci_wakeup_endpoint,
};
-static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
+static void usb_xhci_init(XHCIState *xhci)
{
+ DeviceState *dev = DEVICE(xhci);
XHCIPort *port;
int i, usbports, speedmask;
@@ -3281,7 +3300,7 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
usbports = MAX(xhci->numports_2, xhci->numports_3);
xhci->numports = xhci->numports_2 + xhci->numports_3;
- usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev);
+ usb_bus_new(&xhci->bus, &xhci_bus_ops, dev);
for (i = 0; i < usbports; i++) {
speedmask = 0;
@@ -3313,14 +3332,14 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
{
int i, ret;
- XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
+ XHCIState *xhci = XHCI(dev);
- xhci->pci_dev.config[PCI_CLASS_PROG] = 0x30; /* xHCI */
- xhci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
- xhci->pci_dev.config[PCI_CACHE_LINE_SIZE] = 0x10;
- xhci->pci_dev.config[0x60] = 0x30; /* release number */
+ dev->config[PCI_CLASS_PROG] = 0x30; /* xHCI */
+ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
+ dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
+ dev->config[0x60] = 0x30; /* release number */
- usb_xhci_init(xhci, &dev->qdev);
+ usb_xhci_init(xhci);
if (xhci->numintrs > MAXINTRS) {
xhci->numintrs = MAXINTRS;
@@ -3340,7 +3359,7 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
xhci->mfwrap_timer = qemu_new_timer_ns(vm_clock, xhci_mfwrap_timer, xhci);
- xhci->irq = xhci->pci_dev.irq[0];
+ xhci->irq = dev->irq[0];
memory_region_init(&xhci->mem, OBJECT(xhci), "xhci", LEN_REGS);
memory_region_init_io(&xhci->mem_cap, OBJECT(xhci), &xhci_cap_ops, xhci,
@@ -3366,18 +3385,18 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
memory_region_add_subregion(&xhci->mem, offset, &port->mem);
}
- pci_register_bar(&xhci->pci_dev, 0,
+ pci_register_bar(dev, 0,
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
&xhci->mem);
- ret = pcie_endpoint_cap_init(&xhci->pci_dev, 0xa0);
+ ret = pcie_endpoint_cap_init(dev, 0xa0);
assert(ret >= 0);
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
- msi_init(&xhci->pci_dev, 0x70, xhci->numintrs, true, false);
+ msi_init(dev, 0x70, xhci->numintrs, true, false);
}
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) {
- msix_init(&xhci->pci_dev, xhci->numintrs,
+ msix_init(dev, xhci->numintrs,
&xhci->mem, 0, OFF_MSIX_TABLE,
&xhci->mem, 0, OFF_MSIX_PBA,
0x90);
@@ -3389,6 +3408,7 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
static int usb_xhci_post_load(void *opaque, int version_id)
{
XHCIState *xhci = opaque;
+ PCIDevice *pci_dev = PCI_DEVICE(xhci);
XHCISlot *slot;
XHCIEPContext *epctx;
dma_addr_t dcbaap, pctx;
@@ -3404,7 +3424,7 @@ static int usb_xhci_post_load(void *opaque, int version_id)
continue;
}
slot->ctx =
- xhci_mask64(ldq_le_pci_dma(&xhci->pci_dev, dcbaap + 8*slotid));
+ xhci_mask64(ldq_le_pci_dma(pci_dev, dcbaap + 8 * slotid));
xhci_dma_read_u32s(xhci, slot->ctx, slot_ctx, sizeof(slot_ctx));
slot->uport = xhci_lookup_uport(xhci, slot_ctx);
assert(slot->uport && slot->uport->dev);
@@ -3429,9 +3449,9 @@ static int usb_xhci_post_load(void *opaque, int version_id)
for (intr = 0; intr < xhci->numintrs; intr++) {
if (xhci->intr[intr].msix_used) {
- msix_vector_use(&xhci->pci_dev, intr);
+ msix_vector_use(pci_dev, intr);
} else {
- msix_vector_unuse(&xhci->pci_dev, intr);
+ msix_vector_unuse(pci_dev, intr);
}
}
@@ -3524,8 +3544,8 @@ static const VMStateDescription vmstate_xhci = {
.version_id = 1,
.post_load = usb_xhci_post_load,
.fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(pci_dev, XHCIState),
- VMSTATE_MSIX(pci_dev, XHCIState),
+ VMSTATE_PCIE_DEVICE(parent_obj, XHCIState),
+ VMSTATE_MSIX(parent_obj, XHCIState),
VMSTATE_STRUCT_VARRAY_UINT32(ports, XHCIState, numports, 1,
vmstate_xhci_port, XHCIPort),
@@ -3581,7 +3601,7 @@ static void xhci_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo xhci_info = {
- .name = "nec-usb-xhci",
+ .name = TYPE_XHCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(XHCIState),
.class_init = xhci_class_init,
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index cbe6d51f7a..1ba53d9cc3 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -1,6 +1,7 @@
common-obj-y += virtio-rng.o
common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-y += virtio-bus.o
+common-obj-y += virtio-mmio.o
common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += dataplane/
obj-y += virtio.o virtio-balloon.o
diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c
index e0d6e83625..82cc151b17 100644
--- a/hw/virtio/dataplane/vring.c
+++ b/hw/virtio/dataplane/vring.c
@@ -39,8 +39,8 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096);
- vring->last_avail_idx = 0;
- vring->last_used_idx = 0;
+ vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n);
+ vring->last_used_idx = vring->vr.used->idx;
vring->signalled_used = 0;
vring->signalled_used_valid = false;
@@ -49,8 +49,10 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
return true;
}
-void vring_teardown(Vring *vring)
+void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
{
+ virtio_queue_set_last_avail_idx(vdev, n, vring->last_avail_idx);
+
hostmem_finalize(&vring->hostmem);
}
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
new file mode 100644
index 0000000000..54d6679516
--- /dev/null
+++ b/hw/virtio/virtio-mmio.c
@@ -0,0 +1,421 @@
+/*
+ * Virtio MMIO bindings
+ *
+ * Copyright (c) 2011 Linaro Limited
+ *
+ * Author:
+ * Peter Maydell <peter.maydell@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/virtio/virtio.h"
+#include "qemu/host-utils.h"
+#include "hw/virtio/virtio-bus.h"
+
+/* #define DEBUG_VIRTIO_MMIO */
+
+#ifdef DEBUG_VIRTIO_MMIO
+
+#define DPRINTF(fmt, ...) \
+do { printf("virtio_mmio: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+/* QOM macros */
+/* virtio-mmio-bus */
+#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus"
+#define VIRTIO_MMIO_BUS(obj) \
+ OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS)
+#define VIRTIO_MMIO_BUS_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS)
+#define VIRTIO_MMIO_BUS_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS)
+
+/* virtio-mmio */
+#define TYPE_VIRTIO_MMIO "virtio-mmio"
+#define VIRTIO_MMIO(obj) \
+ OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
+
+/* Memory mapped register offsets */
+#define VIRTIO_MMIO_MAGIC 0x0
+#define VIRTIO_MMIO_VERSION 0x4
+#define VIRTIO_MMIO_DEVICEID 0x8
+#define VIRTIO_MMIO_VENDORID 0xc
+#define VIRTIO_MMIO_HOSTFEATURES 0x10
+#define VIRTIO_MMIO_HOSTFEATURESSEL 0x14
+#define VIRTIO_MMIO_GUESTFEATURES 0x20
+#define VIRTIO_MMIO_GUESTFEATURESSEL 0x24
+#define VIRTIO_MMIO_GUESTPAGESIZE 0x28
+#define VIRTIO_MMIO_QUEUESEL 0x30
+#define VIRTIO_MMIO_QUEUENUMMAX 0x34
+#define VIRTIO_MMIO_QUEUENUM 0x38
+#define VIRTIO_MMIO_QUEUEALIGN 0x3c
+#define VIRTIO_MMIO_QUEUEPFN 0x40
+#define VIRTIO_MMIO_QUEUENOTIFY 0x50
+#define VIRTIO_MMIO_INTERRUPTSTATUS 0x60
+#define VIRTIO_MMIO_INTERRUPTACK 0x64
+#define VIRTIO_MMIO_STATUS 0x70
+/* Device specific config space starts here */
+#define VIRTIO_MMIO_CONFIG 0x100
+
+#define VIRT_MAGIC 0x74726976 /* 'virt' */
+#define VIRT_VERSION 1
+#define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
+
+typedef struct {
+ /* Generic */
+ SysBusDevice parent_obj;
+ MemoryRegion iomem;
+ qemu_irq irq;
+ uint32_t host_features;
+ /* Guest accessible state needing migration and reset */
+ uint32_t host_features_sel;
+ uint32_t guest_features_sel;
+ uint32_t guest_page_shift;
+ /* virtio-bus */
+ VirtioBusState bus;
+} VirtIOMMIOProxy;
+
+static void virtio_mmio_bus_new(VirtioBusState *bus, VirtIOMMIOProxy *dev);
+
+static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
+{
+ VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
+ VirtIODevice *vdev = proxy->bus.vdev;
+
+ DPRINTF("virtio_mmio_read offset 0x%x\n", (int)offset);
+
+ if (!vdev) {
+ /* If no backend is present, we treat most registers as
+ * read-as-zero, except for the magic number, version and
+ * vendor ID. This is not strictly sanctioned by the virtio
+ * spec, but it allows us to provide transports with no backend
+ * plugged in which don't confuse Linux's virtio code: the
+ * probe won't complain about the bad magic number, but the
+ * device ID of zero means no backend will claim it.
+ */
+ switch (offset) {
+ case VIRTIO_MMIO_MAGIC:
+ return VIRT_MAGIC;
+ case VIRTIO_MMIO_VERSION:
+ return VIRT_VERSION;
+ case VIRTIO_MMIO_VENDORID:
+ return VIRT_VENDOR;
+ default:
+ return 0;
+ }
+ }
+
+ if (offset >= VIRTIO_MMIO_CONFIG) {
+ offset -= VIRTIO_MMIO_CONFIG;
+ switch (size) {
+ case 1:
+ return virtio_config_readb(vdev, offset);
+ case 2:
+ return virtio_config_readw(vdev, offset);
+ case 4:
+ return virtio_config_readl(vdev, offset);
+ default:
+ abort();
+ }
+ }
+ if (size != 4) {
+ DPRINTF("wrong size access to register!\n");
+ return 0;
+ }
+ switch (offset) {
+ case VIRTIO_MMIO_MAGIC:
+ return VIRT_MAGIC;
+ case VIRTIO_MMIO_VERSION:
+ return VIRT_VERSION;
+ case VIRTIO_MMIO_DEVICEID:
+ return vdev->device_id;
+ case VIRTIO_MMIO_VENDORID:
+ return VIRT_VENDOR;
+ case VIRTIO_MMIO_HOSTFEATURES:
+ if (proxy->host_features_sel) {
+ return 0;
+ }
+ return proxy->host_features;
+ case VIRTIO_MMIO_QUEUENUMMAX:
+ return VIRTQUEUE_MAX_SIZE;
+ case VIRTIO_MMIO_QUEUEPFN:
+ return virtio_queue_get_addr(vdev, vdev->queue_sel)
+ >> proxy->guest_page_shift;
+ case VIRTIO_MMIO_INTERRUPTSTATUS:
+ return vdev->isr;
+ case VIRTIO_MMIO_STATUS:
+ return vdev->status;
+ case VIRTIO_MMIO_HOSTFEATURESSEL:
+ case VIRTIO_MMIO_GUESTFEATURES:
+ case VIRTIO_MMIO_GUESTFEATURESSEL:
+ case VIRTIO_MMIO_GUESTPAGESIZE:
+ case VIRTIO_MMIO_QUEUESEL:
+ case VIRTIO_MMIO_QUEUENUM:
+ case VIRTIO_MMIO_QUEUEALIGN:
+ case VIRTIO_MMIO_QUEUENOTIFY:
+ case VIRTIO_MMIO_INTERRUPTACK:
+ DPRINTF("read of write-only register\n");
+ return 0;
+ default:
+ DPRINTF("bad register offset\n");
+ return 0;
+ }
+ return 0;
+}
+
+static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
+ VirtIODevice *vdev = proxy->bus.vdev;
+
+ DPRINTF("virtio_mmio_write offset 0x%x value 0x%" PRIx64 "\n",
+ (int)offset, value);
+
+ if (!vdev) {
+ /* If no backend is present, we just make all registers
+ * write-ignored. This allows us to provide transports with
+ * no backend plugged in.
+ */
+ return;
+ }
+
+ if (offset >= VIRTIO_MMIO_CONFIG) {
+ offset -= VIRTIO_MMIO_CONFIG;
+ switch (size) {
+ case 1:
+ virtio_config_writeb(vdev, offset, value);
+ break;
+ case 2:
+ virtio_config_writew(vdev, offset, value);
+ break;
+ case 4:
+ virtio_config_writel(vdev, offset, value);
+ break;
+ default:
+ abort();
+ }
+ return;
+ }
+ if (size != 4) {
+ DPRINTF("wrong size access to register!\n");
+ return;
+ }
+ switch (offset) {
+ case VIRTIO_MMIO_HOSTFEATURESSEL:
+ proxy->host_features_sel = value;
+ break;
+ case VIRTIO_MMIO_GUESTFEATURES:
+ if (!proxy->guest_features_sel) {
+ virtio_set_features(vdev, value);
+ }
+ break;
+ case VIRTIO_MMIO_GUESTFEATURESSEL:
+ proxy->guest_features_sel = value;
+ break;
+ case VIRTIO_MMIO_GUESTPAGESIZE:
+ proxy->guest_page_shift = ctz32(value);
+ if (proxy->guest_page_shift > 31) {
+ proxy->guest_page_shift = 0;
+ }
+ DPRINTF("guest page size %" PRIx64 " shift %d\n", value,
+ proxy->guest_page_shift);
+ break;
+ case VIRTIO_MMIO_QUEUESEL:
+ if (value < VIRTIO_PCI_QUEUE_MAX) {
+ vdev->queue_sel = value;
+ }
+ break;
+ case VIRTIO_MMIO_QUEUENUM:
+ DPRINTF("mmio_queue write %d max %d\n", (int)value, VIRTQUEUE_MAX_SIZE);
+ virtio_queue_set_num(vdev, vdev->queue_sel, value);
+ break;
+ case VIRTIO_MMIO_QUEUEALIGN:
+ virtio_queue_set_align(vdev, vdev->queue_sel, value);
+ break;
+ case VIRTIO_MMIO_QUEUEPFN:
+ if (value == 0) {
+ virtio_reset(vdev);
+ } else {
+ virtio_queue_set_addr(vdev, vdev->queue_sel,
+ value << proxy->guest_page_shift);
+ }
+ break;
+ case VIRTIO_MMIO_QUEUENOTIFY:
+ if (value < VIRTIO_PCI_QUEUE_MAX) {
+ virtio_queue_notify(vdev, value);
+ }
+ break;
+ case VIRTIO_MMIO_INTERRUPTACK:
+ vdev->isr &= ~value;
+ virtio_update_irq(vdev);
+ break;
+ case VIRTIO_MMIO_STATUS:
+ virtio_set_status(vdev, value & 0xff);
+ if (vdev->status == 0) {
+ virtio_reset(vdev);
+ }
+ break;
+ case VIRTIO_MMIO_MAGIC:
+ case VIRTIO_MMIO_VERSION:
+ case VIRTIO_MMIO_DEVICEID:
+ case VIRTIO_MMIO_VENDORID:
+ case VIRTIO_MMIO_HOSTFEATURES:
+ case VIRTIO_MMIO_QUEUENUMMAX:
+ case VIRTIO_MMIO_INTERRUPTSTATUS:
+ DPRINTF("write to readonly register\n");
+ break;
+
+ default:
+ DPRINTF("bad register offset\n");
+ }
+}
+
+static const MemoryRegionOps virtio_mem_ops = {
+ .read = virtio_mmio_read,
+ .write = virtio_mmio_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+ int level;
+
+ if (!proxy->bus.vdev) {
+ return;
+ }
+ level = (proxy->bus.vdev->isr != 0);
+ DPRINTF("virtio_mmio setting IRQ %d\n", level);
+ qemu_set_irq(proxy->irq, level);
+}
+
+static unsigned int virtio_mmio_get_features(DeviceState *opaque)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+ return proxy->host_features;
+}
+
+static int virtio_mmio_load_config(DeviceState *opaque, QEMUFile *f)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+ proxy->host_features_sel = qemu_get_be32(f);
+ proxy->guest_features_sel = qemu_get_be32(f);
+ proxy->guest_page_shift = qemu_get_be32(f);
+ return 0;
+}
+
+static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+ qemu_put_be32(f, proxy->host_features_sel);
+ qemu_put_be32(f, proxy->guest_features_sel);
+ qemu_put_be32(f, proxy->guest_page_shift);
+}
+
+static void virtio_mmio_reset(DeviceState *d)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+
+ virtio_bus_reset(&proxy->bus);
+ proxy->host_features_sel = 0;
+ proxy->guest_features_sel = 0;
+ proxy->guest_page_shift = 0;
+}
+
+/* virtio-mmio device */
+
+/* This is called by virtio-bus just after the device is plugged. */
+static void virtio_mmio_device_plugged(DeviceState *opaque)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+ proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+ proxy->host_features = virtio_bus_get_vdev_features(&proxy->bus,
+ proxy->host_features);
+}
+
+static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(d);
+
+ virtio_mmio_bus_new(&proxy->bus, proxy);
+ sysbus_init_irq(sbd, &proxy->irq);
+ memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_mem_ops, proxy,
+ TYPE_VIRTIO_MMIO, 0x200);
+ sysbus_init_mmio(sbd, &proxy->iomem);
+}
+
+static void virtio_mmio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = virtio_mmio_realizefn;
+ dc->reset = virtio_mmio_reset;
+}
+
+static const TypeInfo virtio_mmio_info = {
+ .name = TYPE_VIRTIO_MMIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(VirtIOMMIOProxy),
+ .class_init = virtio_mmio_class_init,
+};
+
+/* virtio-mmio-bus. */
+
+static void virtio_mmio_bus_new(VirtioBusState *bus, VirtIOMMIOProxy *dev)
+{
+ DeviceState *qdev = DEVICE(dev);
+ BusState *qbus;
+
+ qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_MMIO_BUS, qdev, NULL);
+ qbus = BUS(bus);
+ qbus->allow_hotplug = 0;
+}
+
+static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
+{
+ BusClass *bus_class = BUS_CLASS(klass);
+ VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
+
+ k->notify = virtio_mmio_update_irq;
+ k->save_config = virtio_mmio_save_config;
+ k->load_config = virtio_mmio_load_config;
+ k->get_features = virtio_mmio_get_features;
+ k->device_plugged = virtio_mmio_device_plugged;
+ k->has_variable_vring_alignment = true;
+ bus_class->max_dev = 1;
+}
+
+static const TypeInfo virtio_mmio_bus_info = {
+ .name = TYPE_VIRTIO_MMIO_BUS,
+ .parent = TYPE_VIRTIO_BUS,
+ .instance_size = sizeof(VirtioBusState),
+ .class_init = virtio_mmio_bus_class_init,
+};
+
+static void virtio_mmio_register_types(void)
+{
+ type_register_static(&virtio_mmio_bus_info);
+ type_register_static(&virtio_mmio_info);
+}
+
+type_init(virtio_mmio_register_types)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 8176c147e1..09f62c6c70 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -19,8 +19,11 @@
#include "qemu/atomic.h"
#include "hw/virtio/virtio-bus.h"
-/* The alignment to use between consumer and producer parts of vring.
- * x86 pagesize again. */
+/*
+ * The alignment to use between consumer and producer parts of vring.
+ * x86 pagesize again. This is the default, used by transports like PCI
+ * which don't provide a means for the guest to tell the host the alignment.
+ */
#define VIRTIO_PCI_VRING_ALIGN 4096
typedef struct VRingDesc
@@ -54,6 +57,7 @@ typedef struct VRingUsed
typedef struct VRing
{
unsigned int num;
+ unsigned int align;
hwaddr desc;
hwaddr avail;
hwaddr used;
@@ -93,7 +97,7 @@ static void virtqueue_init(VirtQueue *vq)
vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
vq->vring.used = vring_align(vq->vring.avail +
offsetof(VRingAvail, ring[vq->vring.num]),
- VIRTIO_PCI_VRING_ALIGN);
+ vq->vring.align);
}
static inline uint64_t vring_desc_addr(hwaddr desc_pa, int i)
@@ -667,6 +671,14 @@ hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
return vdev->vq[n].pa;
}
+void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
+{
+ if (num <= VIRTQUEUE_MAX_SIZE) {
+ vdev->vq[n].vring.num = num;
+ virtqueue_init(&vdev->vq[n]);
+ }
+}
+
int virtio_queue_get_num(VirtIODevice *vdev, int n)
{
return vdev->vq[n].vring.num;
@@ -679,6 +691,21 @@ int virtio_queue_get_id(VirtQueue *vq)
return vq - &vdev->vq[0];
}
+void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
+{
+ BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
+ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+
+ /* Check that the transport told us it was going to do this
+ * (so a buggy transport will immediately assert rather than
+ * silently failing to migrate this state)
+ */
+ assert(k->has_variable_vring_alignment);
+
+ vdev->vq[n].vring.align = align;
+ virtqueue_init(&vdev->vq[n]);
+}
+
void virtio_queue_notify_vq(VirtQueue *vq)
{
if (vq->vring.desc) {
@@ -719,6 +746,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
abort();
vdev->vq[i].vring.num = queue_size;
+ vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
vdev->vq[i].handle_output = handle_output;
return &vdev->vq[i];
@@ -825,6 +853,9 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
break;
qemu_put_be32(f, vdev->vq[i].vring.num);
+ if (k->has_variable_vring_alignment) {
+ qemu_put_be32(f, vdev->vq[i].vring.align);
+ }
qemu_put_be64(f, vdev->vq[i].pa);
qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
if (k->save_queue) {
@@ -881,6 +912,9 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
for (i = 0; i < num; i++) {
vdev->vq[i].vring.num = qemu_get_be32(f);
+ if (k->has_variable_vring_alignment) {
+ vdev->vq[i].vring.align = qemu_get_be32(f);
+ }
vdev->vq[i].pa = qemu_get_be64(f);
qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
vdev->vq[i].signalled_used_valid = false;
diff --git a/hw/xen/xen_platform.c b/hw/xen/xen_platform.c
index 15d7cf0f6c..6a8ba7e9aa 100644
--- a/hw/xen/xen_platform.c
+++ b/hw/xen/xen_platform.c
@@ -49,7 +49,10 @@
#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
typedef struct PCIXenPlatformState {
- PCIDevice pci_dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
MemoryRegion fixed_io;
MemoryRegion bar;
MemoryRegion mmio_bar;
@@ -62,6 +65,10 @@ typedef struct PCIXenPlatformState {
int log_buffer_off;
} PCIXenPlatformState;
+#define TYPE_XEN_PLATFORM "xen-platform"
+#define XEN_PLATFORM(obj) \
+ OBJECT_CHECK(PCIXenPlatformState, (obj), TYPE_XEN_PLATFORM)
+
#define XEN_PLATFORM_IOPORT 0x10
/* Send bytes to syslog */
@@ -88,7 +95,7 @@ static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
PCI_CLASS_NETWORK_ETHERNET
&& strcmp(d->name, "xen-pci-passthrough") != 0) {
- qdev_free(&d->qdev);
+ qdev_free(DEVICE(d));
}
}
@@ -103,7 +110,7 @@ static void unplug_disks(PCIBus *b, PCIDevice *d, void *o)
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
PCI_CLASS_STORAGE_IDE
&& strcmp(d->name, "xen-pci-passthrough") != 0) {
- qdev_unplug(&(d->qdev), NULL);
+ qdev_unplug(DEVICE(d), NULL);
}
}
@@ -117,7 +124,8 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
PCIXenPlatformState *s = opaque;
switch (addr) {
- case 0:
+ case 0: {
+ PCIDevice *pci_dev = PCI_DEVICE(s);
/* Unplug devices. Value is a bitmask of which devices to
unplug, with bit 0 the IDE devices, bit 1 the network
devices, and bit 2 the non-primary-master IDE devices. */
@@ -125,16 +133,17 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
DPRINTF("unplug disks\n");
bdrv_drain_all();
bdrv_flush_all();
- pci_unplug_disks(s->pci_dev.bus);
+ pci_unplug_disks(pci_dev->bus);
}
if (val & UNPLUG_ALL_NICS) {
DPRINTF("unplug nics\n");
- pci_unplug_nics(s->pci_dev.bus);
+ pci_unplug_nics(pci_dev->bus);
}
if (val & UNPLUG_AUX_IDE_DISKS) {
DPRINTF("unplug auxiliary disks not supported\n");
}
break;
+ }
case 2:
switch (val) {
case 1:
@@ -368,7 +377,7 @@ static const VMStateDescription vmstate_xen_platform = {
.minimum_version_id_old = 4,
.post_load = xen_platform_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
+ VMSTATE_PCI_DEVICE(parent_obj, PCIXenPlatformState),
VMSTATE_UINT8(flags, PCIXenPlatformState),
VMSTATE_END_OF_LIST()
}
@@ -376,10 +385,10 @@ static const VMStateDescription vmstate_xen_platform = {
static int xen_platform_initfn(PCIDevice *dev)
{
- PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
+ PCIXenPlatformState *d = XEN_PLATFORM(dev);
uint8_t *pci_conf;
- pci_conf = d->pci_dev.config;
+ pci_conf = dev->config;
pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
@@ -388,11 +397,11 @@ static int xen_platform_initfn(PCIDevice *dev)
pci_conf[PCI_INTERRUPT_PIN] = 1;
platform_ioport_bar_setup(d);
- pci_register_bar(&d->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
/* reserve 16MB mmio address for share memory*/
platform_mmio_setup(d);
- pci_register_bar(&d->pci_dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
&d->mmio_bar);
platform_fixed_ioport_init(d);
@@ -402,7 +411,7 @@ static int xen_platform_initfn(PCIDevice *dev)
static void platform_reset(DeviceState *dev)
{
- PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
+ PCIXenPlatformState *s = XEN_PLATFORM(dev);
platform_fixed_ioport_reset(s);
}
@@ -425,7 +434,7 @@ static void xen_platform_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo xen_platform_info = {
- .name = "xen-platform",
+ .name = TYPE_XEN_PLATFORM,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIXenPlatformState),
.class_init = xen_platform_class_init,
diff --git a/hw/xtensa/xtensa_lx60.c b/hw/xtensa/xtensa_lx60.c
index 075daf1893..1138666ca5 100644
--- a/hw/xtensa/xtensa_lx60.c
+++ b/hw/xtensa/xtensa_lx60.c
@@ -144,9 +144,11 @@ static void lx60_net_init(MemoryRegion *address_space,
memory_region_add_subregion(address_space, buffers, ram);
}
-static uint64_t translate_phys_addr(void *env, uint64_t addr)
+static uint64_t translate_phys_addr(void *opaque, uint64_t addr)
{
- return cpu_get_phys_page_debug(env, addr);
+ XtensaCPU *cpu = opaque;
+
+ return cpu_get_phys_page_debug(CPU(cpu), addr);
}
static void lx60_reset(void *opaque)
@@ -252,7 +254,7 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
}
uint64_t elf_entry;
uint64_t elf_lowaddr;
- int success = load_elf(kernel_filename, translate_phys_addr, env,
+ int success = load_elf(kernel_filename, translate_phys_addr, cpu,
&elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0);
if (success > 0) {
env->pc = elf_entry;
diff --git a/hw/xtensa/xtensa_sim.c b/hw/xtensa/xtensa_sim.c
index a88707e161..ea91162b63 100644
--- a/hw/xtensa/xtensa_sim.c
+++ b/hw/xtensa/xtensa_sim.c
@@ -32,9 +32,11 @@
#include "exec/memory.h"
#include "exec/address-spaces.h"
-static uint64_t translate_phys_addr(void *env, uint64_t addr)
+static uint64_t translate_phys_addr(void *opaque, uint64_t addr)
{
- return cpu_get_phys_page_debug(env, addr);
+ XtensaCPU *cpu = opaque;
+
+ return cpu_get_phys_page_debug(CPU(cpu), addr);
}
static void sim_reset(void *opaque)
@@ -88,10 +90,10 @@ static void xtensa_sim_init(QEMUMachineInitArgs *args)
uint64_t elf_entry;
uint64_t elf_lowaddr;
#ifdef TARGET_WORDS_BIGENDIAN
- int success = load_elf(kernel_filename, translate_phys_addr, env,
+ int success = load_elf(kernel_filename, translate_phys_addr, cpu,
&elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
#else
- int success = load_elf(kernel_filename, translate_phys_addr, env,
+ int success = load_elf(kernel_filename, translate_phys_addr, cpu,
&elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
#endif
if (success > 0) {
diff --git a/include/block/aio.h b/include/block/aio.h
index 183679374f..cc77771c46 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -17,6 +17,7 @@
#include "qemu-common.h"
#include "qemu/queue.h"
#include "qemu/event_notifier.h"
+#include "qemu/thread.h"
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
@@ -53,6 +54,8 @@ typedef struct AioContext {
*/
int walking_handlers;
+ /* lock to protect between bh's adders and deleter */
+ QemuMutex bh_lock;
/* Anchor of the list of Bottom Halves belonging to the context */
struct QEMUBH *first_bh;
@@ -127,6 +130,8 @@ void aio_notify(AioContext *ctx);
* aio_bh_poll: Poll bottom halves for an AioContext.
*
* These are internal functions used by the QEMU main loop.
+ * And notice that multiple occurrences of aio_bh_poll cannot
+ * be called concurrently
*/
int aio_bh_poll(AioContext *ctx);
@@ -163,6 +168,8 @@ void qemu_bh_cancel(QEMUBH *bh);
* Deleting a bottom half frees the memory that was allocated for it by
* qemu_bh_new. It also implies canceling the bottom half if it was
* scheduled.
+ * This func is async. The bottom half will do the delete action at the finial
+ * end.
*
* @bh: The bottom half to be deleted.
*/
diff --git a/include/block/block.h b/include/block/block.h
index b6b9014a9c..742fce5f7f 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -157,6 +157,8 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
+int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors);
int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov);
int bdrv_pread(BlockDriverState *bs, int64_t offset,
void *buf, int count);
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 5084202217..a407b50f4a 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -22,6 +22,7 @@
#include "qemu-common.h"
#include "exec/cpu-common.h"
#include "qemu/thread.h"
+#include "qom/cpu.h"
/* some important defines:
*
@@ -209,11 +210,15 @@ extern unsigned long reserved_va;
})
#endif
-#define h2g(x) ({ \
+#define h2g_nocheck(x) ({ \
unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \
+ (abi_ulong)__ret; \
+})
+
+#define h2g(x) ({ \
/* Check if given address fits target address space */ \
assert(h2g_valid(x)); \
- (abi_ulong)__ret; \
+ h2g_nocheck(x); \
})
#define saddr(x) g2h(x)
@@ -428,19 +433,8 @@ int cpu_watchpoint_remove(CPUArchState *env, target_ulong addr,
void cpu_watchpoint_remove_by_ref(CPUArchState *env, CPUWatchpoint *watchpoint);
void cpu_watchpoint_remove_all(CPUArchState *env, int mask);
-#define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */
-#define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */
-#define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */
-
-void cpu_single_step(CPUArchState *env, int enabled);
-
#if !defined(CONFIG_USER_ONLY)
-/* Return the physical page corresponding to a virtual one. Use it
- only for debugging because no protection checks are done. Return -1
- if no page found. */
-hwaddr cpu_get_phys_page_debug(CPUArchState *env, target_ulong addr);
-
/* memory API */
extern ram_addr_t ram_size;
@@ -494,7 +488,7 @@ void qemu_mutex_lock_ramlist(void);
void qemu_mutex_unlock_ramlist(void);
#endif /* !CONFIG_USER_ONLY */
-int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr,
+int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
uint8_t *buf, int len, int is_write);
#endif /* CPU_ALL_H */
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index 5321171cef..a5c028c536 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -168,13 +168,10 @@ typedef struct CPUWatchpoint {
/* from this point: preserved by CPU reset */ \
/* ice debug support */ \
QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints; \
- int singlestep_enabled; \
\
QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints; \
CPUWatchpoint *watchpoint_hit; \
\
- struct GDBRegisterState *gdb_regs; \
- \
/* Core interrupt code */ \
sigjmp_buf jmp_env; \
int exception_index; \
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index ded4160e57..7ea1ad7f9c 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -11,7 +11,7 @@
#define GDB_WATCHPOINT_ACCESS 4
#ifdef NEED_CPU_H
-typedef void (*gdb_syscall_complete_cb)(CPUArchState *env,
+typedef void (*gdb_syscall_complete_cb)(CPUState *cpu,
target_ulong ret, target_ulong err);
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
@@ -20,19 +20,19 @@ void gdb_set_stop_cpu(CPUState *cpu);
void gdb_exit(CPUArchState *, int);
#ifdef CONFIG_USER_ONLY
int gdb_queuesig (void);
-int gdb_handlesig (CPUArchState *, int);
+int gdb_handlesig(CPUState *, int);
void gdb_signalled(CPUArchState *, int);
void gdbserver_fork(CPUArchState *);
#endif
/* Get or set a register. Returns the size of the register. */
typedef int (*gdb_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
-void gdb_register_coprocessor(CPUArchState *env,
+void gdb_register_coprocessor(CPUState *cpu,
gdb_reg_cb get_reg, gdb_reg_cb set_reg,
int num_regs, const char *xml, int g_pos);
static inline int cpu_index(CPUState *cpu)
{
-#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
+#if defined(CONFIG_USER_ONLY)
return cpu->host_tid;
#else
return cpu->cpu_index + 1;
diff --git a/include/exec/softmmu-semi.h b/include/exec/softmmu-semi.h
index 93798b9614..8401f7d587 100644
--- a/include/exec/softmmu-semi.h
+++ b/include/exec/softmmu-semi.h
@@ -13,14 +13,14 @@ static inline uint32_t softmmu_tget32(CPUArchState *env, uint32_t addr)
{
uint32_t val;
- cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 0);
return tswap32(val);
}
static inline uint32_t softmmu_tget8(CPUArchState *env, uint32_t addr)
{
uint8_t val;
- cpu_memory_rw_debug(env, addr, &val, 1, 0);
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr, &val, 1, 0);
return val;
}
@@ -31,7 +31,7 @@ static inline uint32_t softmmu_tget8(CPUArchState *env, uint32_t addr)
static inline void softmmu_tput32(CPUArchState *env, uint32_t addr, uint32_t val)
{
val = tswap32(val);
- cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 1);
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 1);
}
#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; })
#define put_user_ual(arg, p) put_user_u32(arg, p)
@@ -42,8 +42,9 @@ static void *softmmu_lock_user(CPUArchState *env, uint32_t addr, uint32_t len,
uint8_t *p;
/* TODO: Make this something that isn't fixed size. */
p = malloc(len);
- if (p && copy)
- cpu_memory_rw_debug(env, addr, p, len, 0);
+ if (p && copy) {
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr, p, len, 0);
+ }
return p;
}
#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
@@ -58,7 +59,7 @@ static char *softmmu_lock_user_string(CPUArchState *env, uint32_t addr)
return NULL;
}
do {
- cpu_memory_rw_debug(env, addr, &c, 1, 0);
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr, &c, 1, 0);
addr++;
*(p++) = c;
} while (c);
@@ -68,8 +69,9 @@ static char *softmmu_lock_user_string(CPUArchState *env, uint32_t addr)
static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
target_ulong len)
{
- if (len)
- cpu_memory_rw_debug(env, addr, p, len, 1);
+ if (len) {
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr, p, len, 1);
+ }
free(p);
}
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index 7b2b02daaf..bae87c6273 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -55,6 +55,10 @@ struct arm_boot_info {
const struct arm_boot_info *info);
void (*secondary_cpu_reset_hook)(ARMCPU *cpu,
const struct arm_boot_info *info);
+ /* if a board needs to be able to modify a device tree provided by
+ * the user it should implement this hook.
+ */
+ void (*modify_dtb)(const struct arm_boot_info *info, void *fdt);
/* Used internally by arm_boot.c */
int is_linux;
hwaddr initrd_start;
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 61ff154c7d..7fb97b08a2 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -231,6 +231,10 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
.driver = "Nehalem-" TYPE_X86_CPU,\
.property = "level",\
.value = stringify(2),\
+ },{\
+ .driver = "virtio-net-pci",\
+ .property = "any_layout",\
+ .value = "off",\
}
#define PC_COMPAT_1_4 \
diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h
index e1bf96ca69..495bcf3a08 100644
--- a/include/hw/isa/isa.h
+++ b/include/hw/isa/isa.h
@@ -92,9 +92,6 @@ static inline ISABus *isa_bus_from_device(ISADevice *d)
extern hwaddr isa_mem_base;
-void isa_mmio_setup(MemoryRegion *mr, hwaddr size);
-void isa_mmio_init(hwaddr base, hwaddr size);
-
/* dma.c */
int DMA_get_channel_mode (int nchan);
int DMA_read_memory (int nchan, void *buf, int pos, int size);
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 15d4cc9a55..eb9c9a3612 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -17,6 +17,19 @@ int load_aout(const char *filename, hwaddr addr, int max_sz,
int load_uimage(const char *filename, hwaddr *ep,
hwaddr *loadaddr, int *is_linux);
+/**
+ * load_ramdisk:
+ * @filename: Path to the ramdisk image
+ * @addr: Memory address to load the ramdisk to
+ * @max_sz: Maximum allowed ramdisk size (for non-u-boot ramdisks)
+ *
+ * Load a ramdisk image with U-Boot header to the specified memory
+ * address.
+ *
+ * Returns the size of the loaded image on success, -1 otherwise.
+ */
+int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz);
+
ssize_t read_targphys(const char *name,
int fd, hwaddr dst_addr, size_t nbytes);
void pstrcpy_targphys(const char *name,
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index b0838319a9..3cb631eeae 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -43,7 +43,10 @@
OBJECT_CHECK(MCHPCIState, (obj), TYPE_MCH_PCI_DEVICE)
typedef struct MCHPCIState {
- PCIDevice d;
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
MemoryRegion *ram_memory;
MemoryRegion *pci_address_space;
MemoryRegion *system_memory;
@@ -59,7 +62,10 @@ typedef struct MCHPCIState {
} MCHPCIState;
typedef struct Q35PCIHost {
- PCIExpressHost host;
+ /*< private >*/
+ PCIExpressHost parent_obj;
+ /*< public >*/
+
MCHPCIState mch;
} Q35PCIHost;
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index 1868f7aea8..1d8f9973c7 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -37,6 +37,7 @@ PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
+void pci_bridge_update_mappings(PCIBridge *br);
void pci_bridge_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len);
void pci_bridge_disable_base_limit(PCIDevice *dev);
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index 08f8161524..d7933bfd16 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -39,7 +39,7 @@
#define PCI_CLASS_BRIDGE_HOST 0x0600
#define PCI_CLASS_BRIDGE_ISA 0x0601
#define PCI_CLASS_BRIDGE_PCI 0x0604
-#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01
+#define PCI_CLASS_BRIDGE_PCI_INF_SUB 0x01
#define PCI_CLASS_BRIDGE_OTHER 0x0680
#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 9786e00642..87865313eb 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -162,8 +162,8 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
int unit, bool removable, int bootindex,
- const char *serial);
-int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
+ const char *serial, Error **errp);
+void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, Error **errp);
/*
* Predefined sense codes
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
index 7c2e3163fb..8c17165cf2 100644
--- a/include/hw/sysbus.h
+++ b/include/hw/sysbus.h
@@ -23,8 +23,20 @@ typedef struct SysBusDevice SysBusDevice;
#define SYS_BUS_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(SysBusDeviceClass, (obj), TYPE_SYS_BUS_DEVICE)
+/**
+ * SysBusDeviceClass:
+ * @init: Callback function invoked when the #DeviceState.realized property
+ * is changed to %true. Deprecated, new types inheriting directly from
+ * TYPE_SYS_BUS_DEVICE should use #DeviceClass.realize instead, new leaf
+ * types should consult their respective parent type.
+ *
+ * SysBusDeviceClass is not overriding #DeviceClass.realize, so derived
+ * classes overriding it are not required to invoke its implementation.
+ */
typedef struct SysBusDeviceClass {
+ /*< private >*/
DeviceClass parent_class;
+ /*< public >*/
int (*init)(SysBusDevice *dev);
} SysBusDeviceClass;
diff --git a/include/hw/virtio/dataplane/vring.h b/include/hw/virtio/dataplane/vring.h
index 9380cb5413..c0b69ff18f 100644
--- a/include/hw/virtio/dataplane/vring.h
+++ b/include/hw/virtio/dataplane/vring.h
@@ -50,7 +50,7 @@ static inline void vring_set_broken(Vring *vring)
}
bool vring_setup(Vring *vring, VirtIODevice *vdev, int n);
-void vring_teardown(Vring *vring);
+void vring_teardown(Vring *vring, VirtIODevice *vdev, int n);
void vring_disable_notification(VirtIODevice *vdev, Vring *vring);
bool vring_enable_notification(VirtIODevice *vdev, Vring *vring);
bool vring_should_notify(VirtIODevice *vdev, Vring *vring);
diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h
index 9ed60f9c9d..9217f85abc 100644
--- a/include/hw/virtio/virtio-bus.h
+++ b/include/hw/virtio/virtio-bus.h
@@ -62,6 +62,12 @@ typedef struct VirtioBusClass {
* This is called by virtio-bus just before the device is unplugged.
*/
void (*device_unplug)(DeviceState *d);
+ /*
+ * Does the transport have variable vring alignment?
+ * (ie can it ever call virtio_queue_set_align()?)
+ * Note that changing this will break migration for this transport.
+ */
+ bool has_variable_vring_alignment;
} VirtioBusClass;
struct VirtioBusState {
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index b315ac91a4..df60f16a3e 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -243,6 +243,7 @@ struct virtio_net_ctrl_mq {
#define DEFINE_VIRTIO_NET_FEATURES(_state, _field) \
DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
+ DEFINE_PROP_BIT("any_layout", _state, _field, VIRTIO_F_ANY_LAYOUT, true), \
DEFINE_PROP_BIT("csum", _state, _field, VIRTIO_NET_F_CSUM, true), \
DEFINE_PROP_BIT("guest_csum", _state, _field, VIRTIO_NET_F_GUEST_CSUM, true), \
DEFINE_PROP_BIT("gso", _state, _field, VIRTIO_NET_F_GSO, true), \
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index a6c5c5380c..d7e9e0fc8a 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -43,6 +43,8 @@
/* We notify when the ring is completely used, even if the guest is suppressing
* callbacks */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
+/* Can the device handle any descriptor layout? */
+#define VIRTIO_F_ANY_LAYOUT 27
/* We support indirect buffer descriptors */
#define VIRTIO_RING_F_INDIRECT_DESC 28
/* The Guest publishes the used index for which it expects an interrupt
@@ -198,7 +200,9 @@ void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data);
void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data);
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr);
hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n);
+void virtio_queue_set_num(VirtIODevice *vdev, int n, int num);
int virtio_queue_get_num(VirtIODevice *vdev, int n);
+void virtio_queue_set_align(VirtIODevice *vdev, int n, int align);
void virtio_queue_notify(VirtIODevice *vdev, int n);
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n);
void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector);
diff --git a/include/migration/migration.h b/include/migration/migration.h
index f0640e0eec..08c772d4dc 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -49,6 +49,7 @@ struct MigrationState
int64_t dirty_bytes_rate;
bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
int64_t xbzrle_cache_size;
+ int64_t setup_time;
};
void process_incoming_migration(QEMUFile *f);
@@ -77,6 +78,10 @@ void fd_start_incoming_migration(const char *path, Error **errp);
void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp);
+void rdma_start_outgoing_migration(void *opaque, const char *host_port, Error **errp);
+
+void rdma_start_incoming_migration(const char *host_port, Error **errp);
+
void migrate_fd_error(MigrationState *s);
void migrate_fd_connect(MigrationState *s);
@@ -109,6 +114,8 @@ uint64_t xbzrle_mig_pages_transferred(void);
uint64_t xbzrle_mig_pages_overflow(void);
uint64_t xbzrle_mig_pages_cache_miss(void);
+void ram_handle_compressed(void *host, uint8_t ch, uint64_t size);
+
/**
* @migrate_add_blocker - prevent migration from proceeding
*
@@ -124,6 +131,9 @@ void migrate_add_blocker(Error *reason);
void migrate_del_blocker(Error *reason);
bool migrate_rdma_pin_all(void);
+bool migrate_zero_blocks(void);
+
+bool migrate_auto_converge(void);
int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
uint8_t *dst, int dlen);
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 1a6cfcf687..1942cc42fe 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -41,6 +41,7 @@ typedef enum MonitorEvent {
QEVENT_BLOCK_JOB_READY,
QEVENT_DEVICE_DELETED,
QEVENT_DEVICE_TRAY_MOVED,
+ QEVENT_NIC_RX_FILTER_CHANGED,
QEVENT_SUSPEND,
QEVENT_SUSPEND_DISK,
QEVENT_WAKEUP,
diff --git a/include/net/net.h b/include/net/net.h
index 43d85a16eb..30e4b04066 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -49,6 +49,7 @@ typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
typedef void (NetCleanup) (NetClientState *);
typedef void (LinkStatusChanged)(NetClientState *);
typedef void (NetClientDestructor)(NetClientState *);
+typedef RxFilterInfo *(QueryRxFilter)(NetClientState *);
typedef struct NetClientInfo {
NetClientOptionsKind type;
@@ -59,6 +60,7 @@ typedef struct NetClientInfo {
NetCanReceive *can_receive;
NetCleanup *cleanup;
LinkStatusChanged *link_status_changed;
+ QueryRxFilter *query_rx_filter;
NetPoll *poll;
} NetClientInfo;
@@ -74,6 +76,7 @@ struct NetClientState {
unsigned receive_disabled : 1;
NetClientDestructor *destructor;
unsigned int queue_index;
+ unsigned rxfilter_notify_enabled:1;
};
typedef struct NICState {
diff --git a/include/qemu-common.h b/include/qemu-common.h
index f4397388f5..6948bb9177 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -293,6 +293,7 @@ struct qemu_work_item {
void (*func)(void *data);
void *data;
int done;
+ bool free;
};
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index affcc969dc..06e2e6f0ee 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -222,6 +222,56 @@ static inline uint64_t extract64(uint64_t value, int start, int length)
}
/**
+ * sextract32:
+ * @value: the value to extract the bit field from
+ * @start: the lowest bit in the bit field (numbered from 0)
+ * @length: the length of the bit field
+ *
+ * Extract from the 32 bit input @value the bit field specified by the
+ * @start and @length parameters, and return it, sign extended to
+ * an int32_t (ie with the most significant bit of the field propagated
+ * to all the upper bits of the return value). The bit field must lie
+ * entirely within the 32 bit word. It is valid to request that
+ * all 32 bits are returned (ie @length 32 and @start 0).
+ *
+ * Returns: the sign extended value of the bit field extracted from the
+ * input value.
+ */
+static inline int32_t sextract32(uint32_t value, int start, int length)
+{
+ assert(start >= 0 && length > 0 && length <= 32 - start);
+ /* Note that this implementation relies on right shift of signed
+ * integers being an arithmetic shift.
+ */
+ return ((int32_t)(value << (32 - length - start))) >> (32 - length);
+}
+
+/**
+ * sextract64:
+ * @value: the value to extract the bit field from
+ * @start: the lowest bit in the bit field (numbered from 0)
+ * @length: the length of the bit field
+ *
+ * Extract from the 64 bit input @value the bit field specified by the
+ * @start and @length parameters, and return it, sign extended to
+ * an int64_t (ie with the most significant bit of the field propagated
+ * to all the upper bits of the return value). The bit field must lie
+ * entirely within the 64 bit word. It is valid to request that
+ * all 64 bits are returned (ie @length 64 and @start 0).
+ *
+ * Returns: the sign extended value of the bit field extracted from the
+ * input value.
+ */
+static inline uint64_t sextract64(uint64_t value, int start, int length)
+{
+ assert(start >= 0 && length > 0 && length <= 64 - start);
+ /* Note that this implementation relies on right shift of signed
+ * integers being an arithmetic shift.
+ */
+ return ((int64_t)(value << (64 - length - start))) >> (64 - length);
+}
+
+/**
* deposit32:
* @value: initial value to insert bit field into
* @start: the lowest bit in the bit field (numbered from 0)
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 147c256949..daf1835c1a 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -30,6 +30,18 @@
typedef int (*WriteCoreDumpFunction)(void *buf, size_t size, void *opaque);
/**
+ * vaddr:
+ * Type wide enough to contain any #target_ulong virtual address.
+ */
+typedef uint64_t vaddr;
+#define VADDR_PRId PRId64
+#define VADDR_PRIu PRIu64
+#define VADDR_PRIo PRIo64
+#define VADDR_PRIx PRIx64
+#define VADDR_PRIX PRIX64
+#define VADDR_MAX UINT64_MAX
+
+/**
* SECTION:cpu
* @section_id: QEMU-cpu
* @title: CPU Class
@@ -48,6 +60,8 @@ typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr addr,
bool is_write, bool is_exec, int opaque,
unsigned size);
+struct TranslationBlock;
+
/**
* CPUClass:
* @class_by_name: Callback to map -cpu command line model name to an
@@ -56,11 +70,16 @@ typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr addr,
* @reset_dump_flags: #CPUDumpFlags to use for reset logging.
* @do_interrupt: Callback for interrupt handling.
* @do_unassigned_access: Callback for unassigned access handling.
+ * @memory_rw_debug: Callback for GDB memory access.
* @dump_state: Callback for dumping state.
* @dump_statistics: Callback for dumping statistics.
* @get_arch_id: Callback for getting architecture-dependent CPU ID.
* @get_paging_enabled: Callback for inquiring whether paging is enabled.
* @get_memory_mapping: Callback for obtaining the memory mappings.
+ * @set_pc: Callback for setting the Program Counter register.
+ * @synchronize_from_tb: Callback for synchronizing state from a TCG
+ * #TranslationBlock.
+ * @get_phys_page_debug: Callback for obtaining a physical address.
* @vmsd: State description for migration.
*
* Represents a CPU family or model.
@@ -76,6 +95,8 @@ typedef struct CPUClass {
int reset_dump_flags;
void (*do_interrupt)(CPUState *cpu);
CPUUnassignedAccess do_unassigned_access;
+ int (*memory_rw_debug)(CPUState *cpu, vaddr addr,
+ uint8_t *buf, int len, bool is_write);
void (*dump_state)(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
void (*dump_statistics)(CPUState *cpu, FILE *f,
@@ -84,6 +105,9 @@ typedef struct CPUClass {
bool (*get_paging_enabled)(const CPUState *cpu);
void (*get_memory_mapping)(CPUState *cpu, MemoryMappingList *list,
Error **errp);
+ void (*set_pc)(CPUState *cpu, vaddr value);
+ void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
+ hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
const struct VMStateDescription *vmsd;
int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
@@ -114,8 +138,10 @@ struct kvm_run;
* @stopped: Indicates the CPU has been artificially stopped.
* @tcg_exit_req: Set to force TCG to stop executing linked TBs for this
* CPU and return to its top level loop.
+ * @singlestep_enabled: Flags for single-stepping.
* @env_ptr: Pointer to subclass-specific CPUArchState field.
* @current_tb: Currently executing TB.
+ * @gdb_regs: Additional GDB registers.
* @next_cpu: Next CPU sharing TB cache.
* @kvm_fd: vCPU file descriptor for KVM.
*
@@ -146,9 +172,11 @@ struct CPUState {
volatile sig_atomic_t exit_request;
volatile sig_atomic_t tcg_exit_req;
uint32_t interrupt_request;
+ int singlestep_enabled;
void *env_ptr; /* CPUArchState */
struct TranslationBlock *current_tb;
+ struct GDBRegisterState *gdb_regs;
CPUState *next_cpu;
int kvm_fd;
@@ -259,6 +287,25 @@ void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
void cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
+#ifndef CONFIG_USER_ONLY
+/**
+ * cpu_get_phys_page_debug:
+ * @cpu: The CPU to obtain the physical page address for.
+ * @addr: The virtual address.
+ *
+ * Obtains the physical page corresponding to a virtual one.
+ * Use it only for debugging because no protection checks are done.
+ *
+ * Returns: Corresponding physical page address or -1 if no page found.
+ */
+static inline hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ return cc->get_phys_page_debug(cpu, addr);
+}
+#endif
+
/**
* cpu_reset:
* @cpu: The CPU whose state is to be reset.
@@ -277,59 +324,6 @@ void cpu_reset(CPUState *cpu);
ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model);
/**
- * cpu_class_set_vmsd:
- * @cc: CPU class
- * @value: Value to set. Unused for %CONFIG_USER_ONLY.
- *
- * Sets #VMStateDescription for @cc.
- *
- * The @value argument is intentionally discarded for the non-softmmu targets
- * to avoid linker errors or excessive preprocessor usage. If this behavior
- * is undesired, you should assign #CPUClass.vmsd directly instead.
- */
-#ifndef CONFIG_USER_ONLY
-static inline void cpu_class_set_vmsd(CPUClass *cc,
- const struct VMStateDescription *value)
-{
- cc->vmsd = value;
-}
-#else
-#define cpu_class_set_vmsd(cc, value) ((cc)->vmsd = NULL)
-#endif
-
-#ifndef CONFIG_USER_ONLY
-static inline void cpu_class_set_do_unassigned_access(CPUClass *cc,
- CPUUnassignedAccess value)
-{
- cc->do_unassigned_access = value;
-}
-#else
-#define cpu_class_set_do_unassigned_access(cc, value) \
- ((cc)->do_unassigned_access = NULL)
-#endif
-
-/**
- * device_class_set_vmsd:
- * @dc: Device class
- * @value: Value to set. Unused for %CONFIG_USER_ONLY.
- *
- * Sets #VMStateDescription for @dc.
- *
- * The @value argument is intentionally discarded for the non-softmmu targets
- * to avoid linker errors or excessive preprocessor usage. If this behavior
- * is undesired, you should assign #DeviceClass.vmsd directly instead.
- */
-#ifndef CONFIG_USER_ONLY
-static inline void device_class_set_vmsd(DeviceClass *dc,
- const struct VMStateDescription *value)
-{
- dc->vmsd = value;
-}
-#else
-#define device_class_set_vmsd(dc, value) ((dc)->vmsd = NULL)
-#endif
-
-/**
* qemu_cpu_has_work:
* @cpu: The vCPU to check.
*
@@ -379,6 +373,16 @@ bool cpu_is_stopped(CPUState *cpu);
void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data);
/**
+ * async_run_on_cpu:
+ * @cpu: The vCPU to run on.
+ * @func: The function to be executed.
+ * @data: Data to pass to the function.
+ *
+ * Schedules the function @func for execution on the vCPU @cpu asynchronously.
+ */
+void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data);
+
+/**
* qemu_for_each_cpu:
* @func: The function to be executed.
* @data: Data to pass to the function.
@@ -479,6 +483,19 @@ void cpu_resume(CPUState *cpu);
*/
void qemu_init_vcpu(CPUState *cpu);
+#define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */
+#define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */
+#define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */
+
+/**
+ * cpu_single_step:
+ * @cpu: CPU to the flags for.
+ * @enabled: Flags to enable.
+ *
+ * Enables or disables single-stepping for @cpu.
+ */
+void cpu_single_step(CPUState *cpu, int enabled);
+
#ifdef CONFIG_SOFTMMU
extern const struct VMStateDescription vmstate_cpu_common;
#else
diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h
index f0b3f35e03..2b58baf8b1 100644
--- a/include/sysemu/device_tree.h
+++ b/include/sysemu/device_tree.h
@@ -51,4 +51,63 @@ int qemu_devtree_add_subnode(void *fdt, const char *name);
void qemu_devtree_dumpdtb(void *fdt, int size);
+/**
+ * qemu_devtree_setprop_sized_cells_from_array:
+ * @fdt: device tree blob
+ * @node_path: node to set property on
+ * @property: property to set
+ * @numvalues: number of values
+ * @values: array of number-of-cells, value pairs
+ *
+ * Set the specified property on the specified node in the device tree
+ * to be an array of cells. The values of the cells are specified via
+ * the values list, which alternates between "number of cells used by
+ * this value" and "value".
+ * number-of-cells must be either 1 or 2 (other values will result in
+ * an error being returned). If a value is too large to fit in the
+ * number of cells specified for it, an error is returned.
+ *
+ * This function is useful because device tree nodes often have cell arrays
+ * which are either lists of addresses or lists of address,size tuples, but
+ * the number of cells used for each element vary depending on the
+ * #address-cells and #size-cells properties of their parent node.
+ * If you know all your cell elements are one cell wide you can use the
+ * simpler qemu_devtree_setprop_cells(). If you're not setting up the
+ * array programmatically, qemu_devtree_setprop_sized_cells may be more
+ * convenient.
+ *
+ * Return value: 0 on success, <0 on error.
+ */
+int qemu_devtree_setprop_sized_cells_from_array(void *fdt,
+ const char *node_path,
+ const char *property,
+ int numvalues,
+ uint64_t *values);
+
+/**
+ * qemu_devtree_setprop_sized_cells:
+ * @fdt: device tree blob
+ * @node_path: node to set property on
+ * @property: property to set
+ * @...: list of number-of-cells, value pairs
+ *
+ * Set the specified property on the specified node in the device tree
+ * to be an array of cells. The values of the cells are specified via
+ * the variable arguments, which alternates between "number of cells
+ * used by this value" and "value".
+ *
+ * This is a convenience wrapper for the function
+ * qemu_devtree_setprop_sized_cells_from_array().
+ *
+ * Return value: 0 on success, <0 on error.
+ */
+#define qemu_devtree_setprop_sized_cells(fdt, node_path, property, ...) \
+ ({ \
+ uint64_t qdt_tmp[] = { __VA_ARGS__ }; \
+ qemu_devtree_setprop_sized_cells_from_array(fdt, node_path, \
+ property, \
+ ARRAY_SIZE(qdt_tmp) / 2, \
+ qdt_tmp); \
+ })
+
#endif /* __DEVICE_TREE_H__ */
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 1e08a85116..f8ac448e0b 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -169,9 +169,9 @@ void *kvm_arch_ram_alloc(ram_addr_t size);
void kvm_setup_guest_memory(void *start, size_t size);
void kvm_flush_coalesced_mmio_buffer(void);
-int kvm_insert_breakpoint(CPUArchState *env, target_ulong addr,
+int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type);
-int kvm_remove_breakpoint(CPUArchState *env, target_ulong addr,
+int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type);
void kvm_remove_all_breakpoints(CPUState *cpu);
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap);
diff --git a/ioport.c b/ioport.c
index 89b17d69f4..79b7f1ae38 100644
--- a/ioport.c
+++ b/ioport.c
@@ -183,6 +183,7 @@ static void portio_write(void *opaque, hwaddr addr, uint64_t data,
static const MemoryRegionOps portio_ops = {
.read = portio_read,
.write = portio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid.unaligned = true,
.impl.unaligned = true,
};
diff --git a/kvm-all.c b/kvm-all.c
index 232c39a610..4fb4ccbeca 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1890,7 +1890,7 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
data.dbg.control = reinject_trap;
- if (env->singlestep_enabled) {
+ if (cpu->singlestep_enabled) {
data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
}
kvm_arch_update_guest_debug(cpu, &data.dbg);
@@ -1900,10 +1900,9 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
return data.err;
}
-int kvm_insert_breakpoint(CPUArchState *env, target_ulong addr,
+int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type)
{
- CPUState *cpu = ENV_GET_CPU(env);
struct kvm_sw_breakpoint *bp;
int err;
@@ -1946,10 +1945,9 @@ int kvm_insert_breakpoint(CPUArchState *env, target_ulong addr,
return 0;
}
-int kvm_remove_breakpoint(CPUArchState *env, target_ulong addr,
+int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type)
{
- CPUState *cpu = ENV_GET_CPU(env);
struct kvm_sw_breakpoint *bp;
int err;
@@ -2022,13 +2020,13 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
return -EINVAL;
}
-int kvm_insert_breakpoint(CPUArchState *env, target_ulong addr,
+int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type)
{
return -EINVAL;
}
-int kvm_remove_breakpoint(CPUArchState *env, target_ulong addr,
+int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type)
{
return -EINVAL;
diff --git a/kvm-stub.c b/kvm-stub.c
index 370c8371d5..7b2233ae82 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -83,13 +83,13 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
return -ENOSYS;
}
-int kvm_insert_breakpoint(CPUArchState *env, target_ulong addr,
+int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type)
{
return -EINVAL;
}
-int kvm_remove_breakpoint(CPUArchState *env, target_ulong addr,
+int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type)
{
return -EINVAL;
diff --git a/ldscripts/alpha.ld b/ldscripts/alpha.ld
deleted file mode 100644
index 906d76bba1..0000000000
--- a/ldscripts/alpha.ld
+++ /dev/null
@@ -1,127 +0,0 @@
-OUTPUT_FORMAT("elf64-alpha", "elf64-alpha",
- "elf64-alpha")
-OUTPUT_ARCH(alpha)
-ENTRY(__start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.text :
- { *(.rel.text) *(.rel.gnu.linkonce.t*) }
- .rela.text :
- { *(.rela.text) *(.rela.gnu.linkonce.t*) }
- .rel.data :
- { *(.rel.data) *(.rel.gnu.linkonce.d*) }
- .rela.data :
- { *(.rela.data) *(.rela.gnu.linkonce.d*) }
- .rel.rodata :
- { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
- .rela.rodata :
- { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.bss : { *(.rel.bss) }
- .rela.bss : { *(.rela.bss) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init : { *(.init) } =0x47ff041f
- .text :
- {
- *(.text)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.gnu.linkonce.t*)
- } =0x47ff041f
- _etext = .;
- PROVIDE (etext = .);
- .fini : { *(.fini) } =0x47ff041f
- .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
- .rodata1 : { *(.rodata1) }
- .reginfo : { *(.reginfo) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x100000) + (. & (0x100000 - 1));
- .data :
- {
- *(.data)
- *(.gnu.linkonce.d*)
- CONSTRUCTORS
- }
- .data1 : { *(.data1) }
- .ctors :
- {
- *(.ctors)
- }
- .dtors :
- {
- *(.dtors)
- }
- .plt : { *(.plt) }
- .got : { *(.got.plt) *(.got) }
- .dynamic : { *(.dynamic) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : { *(.sdata) }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- _end = . ;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
-}
diff --git a/ldscripts/arm.ld b/ldscripts/arm.ld
deleted file mode 100644
index 7f13da9ebb..0000000000
--- a/ldscripts/arm.ld
+++ /dev/null
@@ -1,153 +0,0 @@
-OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
- "elf32-littlearm")
-OUTPUT_ARCH(arm)
-ENTRY(_start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.text :
- { *(.rel.text) *(.rel.gnu.linkonce.t*) }
- .rela.text :
- { *(.rela.text) *(.rela.gnu.linkonce.t*) }
- .rel.data :
- { *(.rel.data) *(.rel.gnu.linkonce.d*) }
- .rela.data :
- { *(.rela.data) *(.rela.gnu.linkonce.d*) }
- .rel.rodata :
- { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
- .rela.rodata :
- { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.bss : { *(.rel.bss) }
- .rela.bss : { *(.rela.bss) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init : { *(.init) } =0x47ff041f
- .text :
- {
- *(.text)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.gnu.linkonce.t*)
- } =0x47ff041f
- _etext = .;
- PROVIDE (etext = .);
- .fini : { *(.fini) } =0x47ff041f
- .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
- .rodata1 : { *(.rodata1) }
- .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
- __exidx_start = .;
- .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
- __exidx_end = .;
- .reginfo : { *(.reginfo) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x100000) + (. & (0x100000 - 1));
- .data :
- {
- *(.gen_code)
- *(.data)
- *(.gnu.linkonce.d*)
- CONSTRUCTORS
- }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .data1 : { *(.data1) }
- .preinit_array :
- {
- PROVIDE (__preinit_array_start = .);
- KEEP (*(.preinit_array))
- PROVIDE (__preinit_array_end = .);
- }
- .init_array :
- {
- PROVIDE (__init_array_start = .);
- KEEP (*(SORT(.init_array.*)))
- KEEP (*(.init_array))
- PROVIDE (__init_array_end = .);
- }
- .fini_array :
- {
- PROVIDE (__fini_array_start = .);
- KEEP (*(.fini_array))
- KEEP (*(SORT(.fini_array.*)))
- PROVIDE (__fini_array_end = .);
- }
- .ctors :
- {
- *(.ctors)
- }
- .dtors :
- {
- *(.dtors)
- }
- .plt : { *(.plt) }
- .got : { *(.got.plt) *(.got) }
- .dynamic : { *(.dynamic) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : { *(.sdata) }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- _end = . ;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
-}
diff --git a/ldscripts/hppa.ld b/ldscripts/hppa.ld
deleted file mode 100644
index 3555b3e8e8..0000000000
--- a/ldscripts/hppa.ld
+++ /dev/null
@@ -1,211 +0,0 @@
-/* Default linker script, for normal executables */
-OUTPUT_FORMAT("elf32-hppa-linux", "elf32-hppa-linux",
- "elf32-hppa-linux")
-OUTPUT_ARCH(hppa:hppa1.1)
-ENTRY(_start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
- .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
- .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
- .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
- .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
- .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
- .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
- .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
- .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
- .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
- .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
- .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
- .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
- .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
- .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
- .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
- .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
- .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
- .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
- .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init :
- {
- KEEP (*(.init))
- } =0x08000240
- .text :
- {
- *(.text .stub .text.* .gnu.linkonce.t.*)
- KEEP (*(.text.*personality*))
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- } =0x08000240
- .fini :
- {
- KEEP (*(.fini))
- } =0x08000240
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .sdata2 :
- {
- *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
- }
- .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
- .PARISC.unwind : { *(.PARISC.unwind) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x10000) + (. & (0x10000 - 1));
- /* Exception handling */
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
- /* Thread Local Storage sections */
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .preinit_array :
- {
- PROVIDE (__preinit_array_start = .);
- KEEP (*(.preinit_array))
- PROVIDE (__preinit_array_end = .);
- }
- .init_array :
- {
- PROVIDE (__init_array_start = .);
- KEEP (*(SORT(.init_array.*)))
- KEEP (*(.init_array))
- PROVIDE (__init_array_end = .);
- }
- .fini_array :
- {
- PROVIDE (__fini_array_start = .);
- KEEP (*(.fini_array))
- KEEP (*(SORT(.fini_array.*)))
- PROVIDE (__fini_array_end = .);
- }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin*.o(.ctors))
- /* We don't want to include the .ctor section from
- the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin*.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
- .dynamic : { *(.dynamic) }
- .data :
- {
- PROVIDE ($global$ = .);
- *(.data .data.* .gnu.linkonce.d.*)
- KEEP (*(.gnu.linkonce.d.*personality*))
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- .plt : { *(.plt) }
- .got : { *(.got.plt) *(.got) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata :
- {
- *(.sdata .sdata.* .gnu.linkonce.s.*)
- }
- _edata = .; PROVIDE (edata = .);
- __bss_start = .;
- .sbss :
- {
- *(.dynsbss)
- *(.sbss .sbss.* .gnu.linkonce.sb.*)
- *(.scommon)
- }
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections.
- FIXME: Why do we need it? When there is no .bss section, we don't
- pad the .data section. */
- . = ALIGN(. != 0 ? 32 / 8 : 1);
- }
- . = ALIGN(32 / 8);
- . = ALIGN(32 / 8);
- _end = .; PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /DISCARD/ : { *(.note.GNU-stack) }
-}
diff --git a/ldscripts/i386.ld b/ldscripts/i386.ld
deleted file mode 100644
index cc3f160af0..0000000000
--- a/ldscripts/i386.ld
+++ /dev/null
@@ -1,153 +0,0 @@
-/* ld script to make i386 Linux kernel
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
- */
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.text :
- { *(.rel.text) *(.rel.gnu.linkonce.t*) }
- .rela.text :
- { *(.rela.text) *(.rela.gnu.linkonce.t*) }
- .rel.data :
- { *(.rel.data) *(.rel.gnu.linkonce.d*) }
- .rela.data :
- { *(.rela.data) *(.rela.gnu.linkonce.d*) }
- .rel.rodata :
- { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
- .rela.rodata :
- { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.bss : { *(.rel.bss) }
- .rela.bss : { *(.rela.bss) }
- .rel.plt :
- {
- *(.rel.plt)
- PROVIDE (__rel_iplt_start = .);
- *(.rel.iplt)
- PROVIDE (__rel_iplt_end = .);
- }
- .rela.plt :
- {
- *(.rela.plt)
- PROVIDE (__rela_iplt_start = .);
- *(.rela.iplt)
- PROVIDE (__rela_iplt_end = .);
- }
- .init : { *(.init) } =0x47ff041f
- .text :
- {
- *(.text)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.gnu.linkonce.t*)
- } =0x47ff041f
- _etext = .;
- PROVIDE (etext = .);
- .fini : { *(.fini) } =0x47ff041f
- . = ALIGN(32 / 8);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { *(.preinit_array) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { *(.init_array) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { *(.fini_array) }
- PROVIDE (__fini_array_end = .);
- .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
- .rodata1 : { *(.rodata1) }
- .reginfo : { *(.reginfo) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x100000) + (. & (0x100000 - 1));
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .data :
- {
- *(.data)
- *(.gnu.linkonce.d*)
- CONSTRUCTORS
- }
- .data1 : { *(.data1) }
- .ctors :
- {
- *(.ctors)
- }
- .dtors :
- {
- *(.dtors)
- }
- .plt : { *(.plt) }
- .got : { *(.got.plt) *(.got) }
- .dynamic : { *(.dynamic) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : { *(.sdata) }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- _end = . ;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
-}
diff --git a/ldscripts/ia64.ld b/ldscripts/ia64.ld
deleted file mode 100644
index 0c377967cd..0000000000
--- a/ldscripts/ia64.ld
+++ /dev/null
@@ -1,209 +0,0 @@
-/* Default linker script, for normal executables */
-OUTPUT_FORMAT("elf64-ia64-little", "elf64-ia64-little",
- "elf64-ia64-little")
-OUTPUT_ARCH(ia64)
-ENTRY(_start)
-/* __DYNAMIC = 0; */
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
- .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
- .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
- .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
- .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
- .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
- .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
- .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
- .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
- .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
- .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
- .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
- .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
- .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
- .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
- .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
- .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
- .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .rela.IA_64.pltoff : { *(.rela.IA_64.pltoff) }
- .init :
- {
- KEEP (*(.init))
- } =0x00300000010070000002000001000400
- .plt : { *(.plt) }
- .text :
- {
- *(.text .stub .text.* .gnu.linkonce.t.*)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- } =0x00300000010070000002000001000400
- .fini :
- {
- KEEP (*(.fini))
- } =0x00300000010070000002000001000400
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
- .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
- .opd : { *(.opd) }
- .IA_64.unwind_info : { *(.IA_64.unwind_info* .gnu.linkonce.ia64unwi.*) }
- .IA_64.unwind : { *(.IA_64.unwind* .gnu.linkonce.ia64unw.*) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x10000) + (. & (0x10000 - 1));
- /* Ensure the __preinit_array_start label is properly aligned. We
- could instead move the label definition inside the section, but
- the linker would then create the section even if it turns out to
- be empty, which isn't pretty. */
- . = ALIGN(64 / 8);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { *(.preinit_array) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { *(.init_array) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { *(.fini_array) }
- PROVIDE (__fini_array_end = .);
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.*)
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { *(.gcc_except_table) }
- .dynamic : { *(.dynamic) }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin*.o(.ctors))
- /* We don't want to include the .ctor section from
- from the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin*.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- /* Ensure __gp is outside the range of any normal data. We need to
- do this to avoid the linker optimizing the code in op.o and getting
- it out of sync with the relocs that we read when processing that
- file. A better solution might be to ensure that the dynamically
- generated code and static qemu code share a single gp-value. */
- __gp = . + 0x200000;
- .got : { *(.got.plt) *(.got) }
- .IA_64.pltoff : { *(.IA_64.pltoff) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata :
- {
- *(.sdata .sdata.* .gnu.linkonce.s.*)
- }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .sbss :
- {
- PROVIDE (__sbss_start = .);
- PROVIDE (___sbss_start = .);
- *(.dynsbss)
- *(.sbss .sbss.* .gnu.linkonce.sb.*)
- *(.scommon)
- PROVIDE (__sbss_end = .);
- PROVIDE (___sbss_end = .);
- }
- .bss :
- {
- . += 0x400000; /* ensure .bss stuff is out of reach of gp */
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections. */
- . = ALIGN(64 / 8);
- }
- . = ALIGN(64 / 8);
- _end = .;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /DISCARD/ : { *(.note.GNU-stack) }
-}
diff --git a/ldscripts/m68k.ld b/ldscripts/m68k.ld
deleted file mode 100644
index 0e3d9deb5a..0000000000
--- a/ldscripts/m68k.ld
+++ /dev/null
@@ -1,175 +0,0 @@
-/* Script for -z combreloc: combine and sort reloc sections */
-OUTPUT_FORMAT("elf32-m68k", "elf32-m68k",
- "elf32-m68k")
-OUTPUT_ARCH(m68k)
-ENTRY(_start)
-/* __DYNAMIC = 0; */
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.dyn :
- {
- *(.rel.init)
- *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
- *(.rel.fini)
- *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
- *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
- *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
- *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
- *(.rel.ctors)
- *(.rel.dtors)
- *(.rel.got)
- *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
- }
- .rela.dyn :
- {
- *(.rela.init)
- *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
- *(.rela.fini)
- *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
- *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
- *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
- *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
- *(.rela.ctors)
- *(.rela.dtors)
- *(.rela.got)
- *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
- }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init :
- {
- KEEP (*(.init))
- } =0x4e754e75
- .plt : { *(.plt) }
- .text :
- {
- *(.text .stub .text.* .gnu.linkonce.t.*)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- } =0x4e754e75
- .fini :
- {
- KEEP (*(.fini))
- } =0x4e754e75
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x2000) + (. & (0x2000 - 1));
- /* Ensure the __preinit_array_start label is properly aligned. We
- could instead move the label definition inside the section, but
- the linker would then create the section even if it turns out to
- be empty, which isn't pretty. */
- . = ALIGN(32 / 8);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { *(.preinit_array) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { *(.init_array) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { *(.fini_array) }
- PROVIDE (__fini_array_end = .);
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.*)
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { *(.gcc_except_table) }
- .dynamic : { *(.dynamic) }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin.o(.ctors))
- /* We don't want to include the .ctor section from
- from the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .got : { *(.got.plt) *(.got) }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections. */
- . = ALIGN(32 / 8);
- }
- . = ALIGN(32 / 8);
- _end = .;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
-}
diff --git a/ldscripts/mips.ld b/ldscripts/mips.ld
deleted file mode 100644
index 7b610ceed4..0000000000
--- a/ldscripts/mips.ld
+++ /dev/null
@@ -1,222 +0,0 @@
-/* Default linker script, for normal executables */
-OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips",
- "elf32-tradlittlemips")
-OUTPUT_ARCH(mips)
-ENTRY(__start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .reginfo : { *(.reginfo) }
- .dynamic : { *(.dynamic) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
- .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
- .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
- .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
- .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
- .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
- .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
- .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
- .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
- .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
- .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
- .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
- .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
- .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
- .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
- .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
- .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
- .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
- .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
- .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init :
- {
- KEEP (*(.init))
- } =0x47ff041f
- .plt : { *(.plt) }
- .text :
- {
- _ftext = . ;
- *(.text .stub .text.* .gnu.linkonce.t.*)
- KEEP (*(.text.*personality*))
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.mips16.fn.*) *(.mips16.call.*)
- } =0x47ff041f
- .fini :
- {
- KEEP (*(.fini))
- } =0x47ff041f
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .sdata2 :
- {
- *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
- }
- .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000);
- /* Exception handling */
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
- /* Thread Local Storage sections */
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .preinit_array :
- {
- PROVIDE (__preinit_array_start = .);
- KEEP (*(.preinit_array))
- PROVIDE (__preinit_array_end = .);
- }
- .init_array :
- {
- PROVIDE (__init_array_start = .);
- KEEP (*(SORT(.init_array.*)))
- KEEP (*(.init_array))
- PROVIDE (__init_array_end = .);
- }
- .fini_array :
- {
- PROVIDE (__fini_array_start = .);
- KEEP (*(.fini_array))
- KEEP (*(SORT(.fini_array.*)))
- PROVIDE (__fini_array_end = .);
- }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin*.o(.ctors))
- /* We don't want to include the .ctor section from
- the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin*.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
- . = DATA_SEGMENT_RELRO_END (0, .);
- .data :
- {
- _fdata = . ;
- *(.data .data.* .gnu.linkonce.d.*)
- KEEP (*(.gnu.linkonce.d.*personality*))
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- . = .;
- _gp = ALIGN(16) + 0x7ff0;
- .got : { *(.got.plt) *(.got) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata :
- {
- *(.sdata .sdata.* .gnu.linkonce.s.*)
- }
- .lit8 : { *(.lit8) }
- .lit4 : { *(.lit4) }
- _edata = .; PROVIDE (edata = .);
- __bss_start = .;
- _fbss = .;
- .sbss :
- {
- *(.dynsbss)
- *(.sbss .sbss.* .gnu.linkonce.sb.*)
- *(.scommon)
- }
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections.
- FIXME: Why do we need it? When there is no .bss section, we don't
- pad the .data section. */
- . = ALIGN(. != 0 ? 32 / 8 : 1);
- }
- . = ALIGN(32 / 8);
- . = ALIGN(32 / 8);
- _end = .; PROVIDE (end = .);
- . = DATA_SEGMENT_END (.);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
- .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
- /DISCARD/ : { *(.note.GNU-stack) }
-}
diff --git a/ldscripts/ppc.ld b/ldscripts/ppc.ld
deleted file mode 100644
index 2a0dcad63d..0000000000
--- a/ldscripts/ppc.ld
+++ /dev/null
@@ -1,237 +0,0 @@
-/* ld script to make i386 Linux kernel
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
- */
-OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
-OUTPUT_ARCH(powerpc:common)
-ENTRY(_start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
- .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
- .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
- .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
- .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
- .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
- .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
- .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
- .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
- .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
- .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rela.got1 : { *(.rela.got1) }
- .rela.got2 : { *(.rela.got2) }
- .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
- .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
- .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
- .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
- .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
- .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
- .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
- .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
- .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
- .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
- .rel.plt :
- {
- *(.rel.plt)
- PROVIDE (__rel_iplt_start = .);
- *(.rel.iplt)
- PROVIDE (__rel_iplt_end = .);
- }
- .rela.plt :
- {
- *(.rela.plt)
- PROVIDE (__rela_iplt_start = .);
- *(.rela.iplt)
- PROVIDE (__rela_iplt_end = .);
- }
- .init :
- {
- KEEP (*(.init))
- } =0
- .text :
- {
- *(.text .stub .text.* .gnu.linkonce.t.*)
- KEEP (*(.text.*personality*))
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.glink)
- } =0x47ff041f
- .fini :
- {
- KEEP (*(.fini))
- } =0x47ff041f
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .sdata2 :
- {
- PROVIDE (_SDA2_BASE_ = 32768);
- *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
- }
- .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000);
- /* Exception handling */
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
- /* Thread Local Storage sections */
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .preinit_array :
- {
- PROVIDE (__preinit_array_start = .);
- KEEP (*(.preinit_array))
- PROVIDE (__preinit_array_end = .);
- }
- .init_array :
- {
- PROVIDE (__init_array_start = .);
- KEEP (*(SORT(.init_array.*)))
- KEEP (*(.init_array))
- PROVIDE (__init_array_end = .);
- }
- .fini_array :
- {
- PROVIDE (__fini_array_start = .);
- KEEP (*(.fini_array))
- KEEP (*(SORT(.fini_array.*)))
- PROVIDE (__fini_array_end = .);
- }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin*.o(.ctors))
- /* We don't want to include the .ctor section from
- the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin*.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
- .got1 : { *(.got1) }
- .got2 : { *(.got2) }
- .dynamic : { *(.dynamic) }
- .got : SPECIAL { *(.got) }
- . = DATA_SEGMENT_RELRO_END (0, .);
- .plt : SPECIAL { *(.plt) }
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.*)
- KEEP (*(.gnu.linkonce.d.*personality*))
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- .got : SPECIAL { *(.got) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata :
- {
- PROVIDE (_SDA_BASE_ = 32768);
- *(.sdata .sdata.* .gnu.linkonce.s.*)
- }
- _edata = .; PROVIDE (edata = .);
- __bss_start = .;
- .sbss :
- {
- PROVIDE (__sbss_start = .); PROVIDE (___sbss_start = .);
- *(.dynsbss)
- *(.sbss .sbss.* .gnu.linkonce.sb.*)
- *(.scommon)
- PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .);
- }
- .plt : SPECIAL { *(.plt) }
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections.
- FIXME: Why do we need it? When there is no .bss section, we don't
- pad the .data section. */
- . = ALIGN(. != 0 ? 32 / 8 : 1);
- }
- . = ALIGN(32 / 8);
- . = ALIGN(32 / 8);
- _end = .; PROVIDE (end = .);
- . = DATA_SEGMENT_END (.);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
- /DISCARD/ : { *(.fixup) }
- /DISCARD/ : { *(.note.GNU-stack) }
-}
diff --git a/ldscripts/ppc64.ld b/ldscripts/ppc64.ld
deleted file mode 100644
index e2dafa0b53..0000000000
--- a/ldscripts/ppc64.ld
+++ /dev/null
@@ -1,230 +0,0 @@
-/* Script for -z combreloc: combine and sort reloc sections */
-OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc",
- "elf64-powerpc")
-OUTPUT_ARCH(powerpc:common64)
-ENTRY(_start)
-/* __DYNAMIC = 0; */
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.dyn :
- {
- *(.rel.init)
- *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
- *(.rel.fini)
- *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
- *(.rel.data.rel.ro*)
- *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
- *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
- *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
- *(.rel.ctors)
- *(.rel.dtors)
- *(.rel.got)
- *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
- *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
- *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
- *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
- *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
- }
- .rela.dyn :
- {
- *(.rela.init)
- *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
- *(.rela.fini)
- *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
- *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
- *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
- *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
- *(.rela.ctors)
- *(.rela.dtors)
- *(.rela.got)
- *(.rela.toc)
- *(.rela.opd)
- *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
- *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
- *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
- *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
- *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
- }
- .rel.plt :
- {
- *(.rel.plt)
- PROVIDE (__rel_iplt_start = .);
- *(.rel.iplt)
- PROVIDE (__rel_iplt_end = .);
- }
- .rela.plt :
- {
- *(.rela.plt)
- PROVIDE (__rela_iplt_start = .);
- *(.rela.iplt)
- PROVIDE (__rela_iplt_end = .);
- }
- .rela.tocbss : { *(.rela.tocbss) }
- .init :
- {
- KEEP (*(.init))
- } =0x60000000
- .text :
- {
- *(.text .stub .text.* .gnu.linkonce.t.*)
- KEEP (*(.text.*personality*))
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.sfpr .glink)
- } =0x60000000
- .fini :
- {
- KEEP (*(.fini))
- } =0x60000000
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
- .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN
-(0x10000, 0x1000); /* Exception handling */
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { KEEP (*(.gcc_except_table))
-*(.gcc_except_table.*) } /* Thread Local Storage sections */
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- /* Ensure the __preinit_array_start label is properly aligned. We
- could instead move the label definition inside the section, but
- the linker would then create the section even if it turns out to
- be empty, which isn't pretty. */
- . = ALIGN(64 / 8);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { KEEP (*(.preinit_array)) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { KEEP (*(.init_array)) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { KEEP (*(.fini_array)) }
- PROVIDE (__fini_array_end = .);
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin*.o(.ctors))
- /* We don't want to include the .ctor section from
- from the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin*.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }
- .dynamic : { *(.dynamic) }
- . = DATA_SEGMENT_RELRO_END (0, .);
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.*)
- KEEP (*(.gnu.linkonce.d.*personality*))
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- .toc1 ALIGN(8) : { *(.toc1) }
- .opd ALIGN(8) : { KEEP (*(.opd)) }
- .got ALIGN(8) : { *(.got .toc) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata :
- {
- *(.sdata .sdata.* .gnu.linkonce.s.*)
- }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .tocbss ALIGN(8) : { *(.tocbss)}
- .sbss :
- {
- PROVIDE (__sbss_start = .);
- PROVIDE (___sbss_start = .);
- *(.dynsbss)
- *(.sbss .sbss.* .gnu.linkonce.sb.*)
- *(.scommon)
- PROVIDE (__sbss_end = .);
- PROVIDE (___sbss_end = .);
- }
- .plt : { *(.plt) }
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections. */
- . = ALIGN(64 / 8);
- }
- . = ALIGN(64 / 8);
- _end = .;
- PROVIDE (end = .);
- . = DATA_SEGMENT_END (.);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /DISCARD/ : { *(.note.GNU-stack) }
-}
diff --git a/ldscripts/s390.ld b/ldscripts/s390.ld
deleted file mode 100644
index a9c53707f1..0000000000
--- a/ldscripts/s390.ld
+++ /dev/null
@@ -1,201 +0,0 @@
-OUTPUT_FORMAT("elf32-s390", "elf32-s390",
- "elf32-s390")
-OUTPUT_ARCH(s390:31-bit)
-ENTRY(_start)
-/* __DYNAMIC = 0; */
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.dyn :
- {
- *(.rel.init)
- *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
- *(.rel.fini)
- *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
- *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
- *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
- *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
- *(.rel.ctors)
- *(.rel.dtors)
- *(.rel.got)
- *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
- *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
- *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
- *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
- *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
- }
- .rela.dyn :
- {
- *(.rela.init)
- *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
- *(.rela.fini)
- *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
- *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
- *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
- *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
- *(.rela.ctors)
- *(.rela.dtors)
- *(.rela.got)
- *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
- *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
- *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
- *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
- *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
- }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init :
- {
- KEEP (*(.init))
- } =0x07070707
- .plt : { *(.plt) }
- .text :
- {
- *(.text .stub .text.* .gnu.linkonce.t.*)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- } =0x07070707
- .fini :
- {
- KEEP (*(.fini))
- } =0x07070707
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
- .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x1000) + (. & (0x1000 - 1));
- /* Ensure the __preinit_array_start label is properly aligned. We
- could instead move the label definition inside the section, but
- the linker would then create the section even if it turns out to
- be empty, which isn't pretty. */
- . = ALIGN(32 / 8);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { *(.preinit_array) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { *(.init_array) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { *(.fini_array) }
- PROVIDE (__fini_array_end = .);
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.*)
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { *(.gcc_except_table) }
- .dynamic : { *(.dynamic) }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin.o(.ctors))
- /* We don't want to include the .ctor section from
- from the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .got : { *(.got.plt) *(.got) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata :
- {
- *(.sdata .sdata.* .gnu.linkonce.s.*)
- }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .sbss :
- {
- PROVIDE (__sbss_start = .);
- PROVIDE (___sbss_start = .);
- *(.dynsbss)
- *(.sbss .sbss.* .gnu.linkonce.sb.*)
- *(.scommon)
- PROVIDE (__sbss_end = .);
- PROVIDE (___sbss_end = .);
- }
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections. */
- . = ALIGN(32 / 8);
- }
- . = ALIGN(32 / 8);
- _end = .;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
-}
diff --git a/ldscripts/sparc.ld b/ldscripts/sparc.ld
deleted file mode 100644
index 56efe34e73..0000000000
--- a/ldscripts/sparc.ld
+++ /dev/null
@@ -1,150 +0,0 @@
-OUTPUT_FORMAT("elf32-sparc", "elf32-sparc",
- "elf32-sparc")
-OUTPUT_ARCH(sparc)
-ENTRY(_start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.text :
- { *(.rel.text) *(.rel.gnu.linkonce.t*) }
- .rela.text :
- { *(.rela.text) *(.rela.gnu.linkonce.t*) }
- .rel.data :
- { *(.rel.data) *(.rel.gnu.linkonce.d*) }
- .rela.data :
- { *(.rela.data) *(.rela.gnu.linkonce.d*) }
- .rel.rodata :
- { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
- .rela.rodata :
- { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.bss : { *(.rel.bss) }
- .rela.bss : { *(.rela.bss) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init : { *(.init) } =0x47ff041f
- .text :
- {
- *(.text)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.gnu.linkonce.t*)
- } =0x47ff041f
- _etext = .;
- PROVIDE (etext = .);
- .fini : { *(.fini) } =0x47ff041f
- .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
- .rodata1 : { *(.rodata1) }
- .reginfo : { *(.reginfo) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x100000) + (. & (0x100000 - 1));
- .data :
- {
- *(.data)
- *(.gnu.linkonce.d*)
- CONSTRUCTORS
- }
- .data1 : { *(.data1) }
- .tdata : { *(.tdata) }
- .tbss : { *(.tbss) }
- .preinit_array :
- {
- PROVIDE (__preinit_array_start = .);
- KEEP (*(.preinit_array))
- PROVIDE (__preinit_array_end = .);
- }
- .init_array :
- {
- PROVIDE (__init_array_start = .);
- KEEP (*(SORT(.init_array.*)))
- KEEP (*(.init_array))
- PROVIDE (__init_array_end = .);
- }
- .fini_array :
- {
- PROVIDE (__fini_array_start = .);
- KEEP (*(.fini_array))
- KEEP (*(SORT(.fini_array.*)))
- PROVIDE (__fini_array_end = .);
- }
- .ctors :
- {
- *(.ctors)
- }
- .dtors :
- {
- *(.dtors)
- }
- .plt : { *(.plt) }
- .got : { *(.got.plt) *(.got) }
- .dynamic : { *(.dynamic) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : { *(.sdata) }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- _end = . ;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
- /DISCARD/ : { *(.note.GNU-stack) *(.note.ABI-tag) }
-}
diff --git a/ldscripts/sparc64.ld b/ldscripts/sparc64.ld
deleted file mode 100644
index 9ea41431e8..0000000000
--- a/ldscripts/sparc64.ld
+++ /dev/null
@@ -1,138 +0,0 @@
-OUTPUT_FORMAT("elf64-sparc", "elf64-sparc",
- "elf64-sparc")
-OUTPUT_ARCH(sparc:v9)
-ENTRY(_start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.text :
- { *(.rel.text) *(.rel.gnu.linkonce.t*) }
- .rela.text :
- { *(.rela.text) *(.rela.gnu.linkonce.t*) }
- .rel.data :
- { *(.rel.data) *(.rel.gnu.linkonce.d*) }
- .rela.data :
- { *(.rela.data) *(.rela.gnu.linkonce.d*) }
- .rel.rodata :
- { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
- .rela.rodata :
- { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.bss : { *(.rel.bss) }
- .rela.bss : { *(.rela.bss) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init : { *(.init) } =0x47ff041f
- .text :
- {
- *(.text)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.gnu.linkonce.t*)
- } =0x47ff041f
- _etext = .;
- PROVIDE (etext = .);
- .fini : { *(.fini) } =0x47ff041f
- .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
- .rodata1 : { *(.rodata1) }
- . = ALIGN(64 / 8);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { *(.preinit_array) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { *(.init_array) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { *(.fini_array) }
- PROVIDE (__fini_array_end = .);
- .reginfo : { *(.reginfo) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x100000) + (. & (0x100000 - 1));
- .data :
- {
- *(.gen_code)
- *(.data)
- *(.gnu.linkonce.d*)
- CONSTRUCTORS
- }
- .data1 : { *(.data1) }
- .ctors :
- {
- *(.ctors)
- }
- .dtors :
- {
- *(.dtors)
- }
- .plt : { *(.plt) }
- .got : { *(.got.plt) *(.got) }
- .dynamic : { *(.dynamic) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : { *(.sdata) }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- _end = . ;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
-}
diff --git a/ldscripts/x86_64.ld b/ldscripts/x86_64.ld
deleted file mode 100644
index b7a9f4eb36..0000000000
--- a/ldscripts/x86_64.ld
+++ /dev/null
@@ -1,180 +0,0 @@
-/* Default linker script, for normal executables */
-OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
-OUTPUT_ARCH(i386:x86-64)
-ENTRY(_start)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.init : { *(.rel.init) }
- .rela.init : { *(.rela.init) }
- .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
- .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
- .rel.fini : { *(.rel.fini) }
- .rela.fini : { *(.rela.fini) }
- .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
- .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
- .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
- .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
- .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
- .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
- .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
- .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
- .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
- .rel.plt :
- {
- *(.rel.plt)
- PROVIDE (__rel_iplt_start = .);
- *(.rel.iplt)
- PROVIDE (__rel_iplt_end = .);
- }
- .rela.plt :
- {
- *(.rela.plt)
- PROVIDE (__rela_iplt_start = .);
- *(.rela.iplt)
- PROVIDE (__rela_iplt_end = .);
- }
- .init :
- {
- KEEP (*(.init))
- } =0x90909090
- .plt : { *(.plt) }
- .text :
- {
- *(.text .stub .text.* .gnu.linkonce.t.*)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- } =0x90909090
- .fini :
- {
- KEEP (*(.fini))
- } =0x90909090
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000);
- /* Ensure the __preinit_array_start label is properly aligned. We
- could instead move the label definition inside the section, but
- the linker would then create the section even if it turns out to
- be empty, which isn't pretty. */
- . = ALIGN(64 / 8);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { *(.preinit_array) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { *(.init_array) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { *(.fini_array) }
- PROVIDE (__fini_array_end = .);
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.*)
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { *(.gcc_except_table) }
- .dynamic : { *(.dynamic) }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin.o(.ctors))
- /* We don't want to include the .ctor section from
- from the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .got : { *(.got.plt) *(.got) }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections. */
- . = ALIGN(64 / 8);
- }
- . = ALIGN(64 / 8);
- _end = .;
- PROVIDE (end = .);
- . = DATA_SEGMENT_END (.);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
-}
diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h
index 003d424701..73f29314f6 100644
--- a/linux-user/arm/syscall.h
+++ b/linux-user/arm/syscall.h
@@ -40,3 +40,5 @@ struct target_pt_regs {
#else
#define UNAME_MACHINE "armv5tel"
#endif
+
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/cpu-uname.c b/linux-user/cpu-uname.c
index 59cd6477d5..cc713e6553 100644
--- a/linux-user/cpu-uname.c
+++ b/linux-user/cpu-uname.c
@@ -55,12 +55,14 @@ const char *cpu_to_uname_machine(void *cpu_env)
return "x86-64";
#elif defined(TARGET_I386)
/* see arch/x86/kernel/cpu/bugs.c: check_bugs(), 386, 486, 586, 686 */
- uint32_t cpuid_version = ((CPUX86State *)cpu_env)->cpuid_version;
- int family = ((cpuid_version >> 8) & 0x0f) + ((cpuid_version >> 20) & 0xff);
- if (family == 4)
+ CPUState *cpu = ENV_GET_CPU((CPUX86State *)cpu_env);
+ int family = object_property_get_int(OBJECT(cpu), "family", NULL);
+ if (family == 4) {
return "i486";
- if (family == 5)
+ }
+ if (family == 5) {
return "i586";
+ }
return "i686";
#else
/* default is #define-d in each arch/ subdir */
diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h
index 50e50b4f3f..832ee64bd8 100644
--- a/linux-user/cris/syscall.h
+++ b/linux-user/cris/syscall.h
@@ -38,4 +38,6 @@ struct target_pt_regs {
unsigned long eda;
};
+#define TARGET_CLONE_BACKWARDS2
+
#endif
diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h
index 266e2c4c83..12b8c3b672 100644
--- a/linux-user/i386/syscall.h
+++ b/linux-user/i386/syscall.h
@@ -144,3 +144,5 @@ struct target_vm86plus_struct {
};
#define UNAME_MACHINE "i686"
+
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/i386/target_cpu.h b/linux-user/i386/target_cpu.h
index abcac79d25..58f86454d6 100644
--- a/linux-user/i386/target_cpu.h
+++ b/linux-user/i386/target_cpu.h
@@ -28,6 +28,21 @@ static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp)
env->regs[R_EAX] = 0;
}
-/* TODO: need to implement cpu_set_tls() */
+#if defined(TARGET_ABI32)
+abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr);
-#endif
+static inline void cpu_set_tls(CPUX86State *env, target_ulong newtls)
+{
+ do_set_thread_area(env, newtls);
+ cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector);
+}
+#else
+abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr);
+
+static inline void cpu_set_tls(CPUX86State *env, target_ulong newtls)
+{
+ do_arch_prctl(env, TARGET_ARCH_SET_FS, newtls);
+}
+#endif /* defined(TARGET_ABI32) */
+
+#endif /* !defined(TARGET_CPU_H) */
diff --git a/linux-user/m68k/target_cpu.h b/linux-user/m68k/target_cpu.h
index 8a2a305a0b..cad9c90dd0 100644
--- a/linux-user/m68k/target_cpu.h
+++ b/linux-user/m68k/target_cpu.h
@@ -29,6 +29,10 @@ static inline void cpu_clone_regs(CPUM68KState *env, target_ulong newsp)
env->dregs[0] = 0;
}
-/* TODO: need to implement cpu_set_tls() */
+static inline void cpu_set_tls(CPUM68KState *env, target_ulong newtls)
+{
+ TaskState *ts = env->opaque;
+ ts->tp_value = newtls;
+}
#endif
diff --git a/linux-user/main.c b/linux-user/main.c
index 7f15d3da2b..5dc09471e4 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -92,7 +92,6 @@ int cpu_get_pic_interrupt(CPUX86State *env)
}
#endif
-#if defined(CONFIG_USE_NPTL)
/***********************************************************/
/* Helper routines for implementing atomic operations. */
@@ -207,43 +206,6 @@ void cpu_list_unlock(void)
{
pthread_mutex_unlock(&cpu_list_mutex);
}
-#else /* if !CONFIG_USE_NPTL */
-/* These are no-ops because we are not threadsafe. */
-static inline void cpu_exec_start(CPUState *cpu)
-{
-}
-
-static inline void cpu_exec_end(CPUState *cpu)
-{
-}
-
-static inline void start_exclusive(void)
-{
-}
-
-static inline void end_exclusive(void)
-{
-}
-
-void fork_start(void)
-{
-}
-
-void fork_end(int child)
-{
- if (child) {
- gdbserver_fork((CPUArchState *)thread_cpu->env_ptr);
- }
-}
-
-void cpu_list_lock(void)
-{
-}
-
-void cpu_list_unlock(void)
-{
-}
-#endif
#ifdef TARGET_I386
@@ -312,6 +274,7 @@ static void set_idt(int n, unsigned int dpl)
void cpu_loop(CPUX86State *env)
{
+ CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr;
abi_ulong pc;
target_siginfo_t info;
@@ -443,7 +406,7 @@ void cpu_loop(CPUX86State *env)
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
@@ -875,7 +838,7 @@ void cpu_loop(CPUARMState *env)
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
@@ -966,7 +929,7 @@ void cpu_loop(CPUUniCore32State *env)
{
int sig;
- sig = gdb_handlesig(env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig) {
info.si_signo = sig;
info.si_errno = 0;
@@ -1233,7 +1196,7 @@ void cpu_loop (CPUSPARCState *env)
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
@@ -1764,7 +1727,7 @@ void cpu_loop(CPUPPCState *env)
{
int sig;
- sig = gdb_handlesig(env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig) {
info.si_signo = sig;
info.si_errno = 0;
@@ -2028,7 +1991,7 @@ static const uint8_t mips_syscall_args[] = {
MIPS_SYS(sys_fremovexattr, 2) /* 4235 */
MIPS_SYS(sys_tkill , 2)
MIPS_SYS(sys_sendfile64 , 5)
- MIPS_SYS(sys_futex , 2)
+ MIPS_SYS(sys_futex , 6)
MIPS_SYS(sys_sched_setaffinity, 3)
MIPS_SYS(sys_sched_getaffinity, 3) /* 4240 */
MIPS_SYS(sys_io_setup , 2)
@@ -2315,7 +2278,7 @@ done_syscall:
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
@@ -2348,7 +2311,31 @@ done_syscall:
abi_ulong trap_instr;
unsigned int code;
- ret = get_user_ual(trap_instr, env->active_tc.PC);
+ if (env->hflags & MIPS_HFLAG_M16) {
+ if (env->insn_flags & ASE_MICROMIPS) {
+ /* microMIPS mode */
+ abi_ulong instr[2];
+
+ ret = get_user_u16(instr[0], env->active_tc.PC) ||
+ get_user_u16(instr[1], env->active_tc.PC + 2);
+
+ trap_instr = (instr[0] << 16) | instr[1];
+ } else {
+ /* MIPS16e mode */
+ ret = get_user_u16(trap_instr, env->active_tc.PC);
+ if (ret != 0) {
+ goto error;
+ }
+ code = (trap_instr >> 6) & 0x3f;
+ if (do_break(env, &info, code) != 0) {
+ goto error;
+ }
+ break;
+ }
+ } else {
+ ret = get_user_ual(trap_instr, env->active_tc.PC);
+ }
+
if (ret != 0) {
goto error;
}
@@ -2372,14 +2359,30 @@ done_syscall:
abi_ulong trap_instr;
unsigned int code = 0;
- ret = get_user_ual(trap_instr, env->active_tc.PC);
+ if (env->hflags & MIPS_HFLAG_M16) {
+ /* microMIPS mode */
+ abi_ulong instr[2];
+
+ ret = get_user_u16(instr[0], env->active_tc.PC) ||
+ get_user_u16(instr[1], env->active_tc.PC + 2);
+
+ trap_instr = (instr[0] << 16) | instr[1];
+ } else {
+ ret = get_user_ual(trap_instr, env->active_tc.PC);
+ }
+
if (ret != 0) {
goto error;
}
/* The immediate versions don't provide a code. */
if (!(trap_instr & 0xFC000000)) {
- code = ((trap_instr >> 6) & ((1 << 10) - 1));
+ if (env->hflags & MIPS_HFLAG_M16) {
+ /* microMIPS mode */
+ code = ((trap_instr >> 12) & ((1 << 4) - 1));
+ } else {
+ code = ((trap_instr >> 6) & ((1 << 10) - 1));
+ }
}
if (do_break(env, &info, code) != 0) {
@@ -2475,7 +2478,7 @@ void cpu_loop(CPUOpenRISCState *env)
break;
}
if (gdbsig) {
- gdb_handlesig(env, gdbsig);
+ gdb_handlesig(cs, gdbsig);
if (gdbsig != TARGET_SIGTRAP) {
exit(1);
}
@@ -2518,7 +2521,7 @@ void cpu_loop(CPUSH4State *env)
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
@@ -2586,7 +2589,7 @@ void cpu_loop(CPUCRISState *env)
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
@@ -2686,7 +2689,7 @@ void cpu_loop(CPUMBState *env)
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
@@ -2779,7 +2782,7 @@ void cpu_loop(CPUM68KState *env)
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
@@ -3006,7 +3009,7 @@ void cpu_loop(CPUAlphaState *env)
}
break;
case EXCP_DEBUG:
- info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
+ info.si_signo = gdb_handlesig(cs, TARGET_SIGTRAP);
if (info.si_signo) {
env->lock_addr = -1;
info.si_errno = 0;
@@ -3059,7 +3062,7 @@ void cpu_loop(CPUS390XState *env)
break;
case EXCP_DEBUG:
- sig = gdb_handlesig(env, TARGET_SIGTRAP);
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
if (sig) {
n = TARGET_TRAP_BRKPT;
goto do_signal_pc;
@@ -3156,12 +3159,7 @@ THREAD CPUState *thread_cpu;
void task_settid(TaskState *ts)
{
if (ts->ts_tid == 0) {
-#ifdef CONFIG_USE_NPTL
ts->ts_tid = (pid_t)syscall(SYS_gettid);
-#else
- /* when no threads are used, tid becomes pid */
- ts->ts_tid = getpid();
-#endif
}
}
@@ -3541,6 +3539,7 @@ int main(int argc, char **argv, char **envp)
struct linux_binprm bprm;
TaskState *ts;
CPUArchState *env;
+ CPUState *cpu;
int optind;
char **target_environ, **wrk;
char **target_argv;
@@ -3637,11 +3636,10 @@ int main(int argc, char **argv, char **envp)
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
-#if defined(TARGET_SPARC) || defined(TARGET_PPC)
+ cpu = ENV_GET_CPU(env);
cpu_reset(ENV_GET_CPU(env));
-#endif
- thread_cpu = ENV_GET_CPU(env);
+ thread_cpu = cpu;
if (getenv("QEMU_STRACE")) {
do_strace = 1;
@@ -4076,7 +4074,7 @@ int main(int argc, char **argv, char **envp)
gdbstub_port);
exit(1);
}
- gdb_handlesig(env, 0);
+ gdb_handlesig(cpu, 0);
}
cpu_loop(env);
/* never exits */
diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h
index c3e5c55b3d..d550989d5e 100644
--- a/linux-user/microblaze/syscall.h
+++ b/linux-user/microblaze/syscall.h
@@ -48,4 +48,6 @@ struct target_pt_regs {
uint32_t kernel_mode;
};
+#define TARGET_CLONE_BACKWARDS
+
#endif
diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h
index 3deb862cc4..9d437d918b 100644
--- a/linux-user/mips/syscall.h
+++ b/linux-user/mips/syscall.h
@@ -225,3 +225,5 @@ struct target_pt_regs {
#define TARGET_QEMU_ESIGRETURN 255
#define UNAME_MACHINE "mips"
+
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
index cd707df32f..1710f766e2 100644
--- a/linux-user/mips64/syscall.h
+++ b/linux-user/mips64/syscall.h
@@ -222,3 +222,5 @@ struct target_pt_regs {
#define TARGET_QEMU_ESIGRETURN 255
#define UNAME_MACHINE "mips64"
+
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index de2219768d..a249f0ceb6 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -33,7 +33,6 @@
//#define DEBUG_MMAP
-#if defined(CONFIG_USE_NPTL)
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
static __thread int mmap_lock_count;
@@ -66,16 +65,6 @@ void mmap_fork_end(int child)
else
pthread_mutex_unlock(&mmap_mutex);
}
-#else
-/* We aren't threadsafe to start with, so no need to worry about locking. */
-void mmap_lock(void)
-{
-}
-
-void mmap_unlock(void)
-{
-}
-#endif
/* NOTE: all the constants are the HOST ones, but addresses are target. */
int target_mprotect(abi_ulong start, abi_ulong len, int prot)
diff --git a/linux-user/openrisc/target_cpu.h b/linux-user/openrisc/target_cpu.h
index 501fb81162..32a46ac840 100644
--- a/linux-user/openrisc/target_cpu.h
+++ b/linux-user/openrisc/target_cpu.h
@@ -25,9 +25,14 @@ static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp)
if (newsp) {
env->gpr[1] = newsp;
}
- env->gpr[2] = 0;
+ env->gpr[11] = 0;
}
-/* TODO: need to implement cpu_set_tls() */
+static inline void cpu_set_tls(CPUOpenRISCState *env, target_ulong newtls)
+{
+ /* Linux kernel 3.10 does not pay any attention to CLONE_SETTLS
+ * in copy_thread(), so QEMU need not do so either.
+ */
+}
#endif
diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h
index 481047b2dd..ba36acbc33 100644
--- a/linux-user/ppc/syscall.h
+++ b/linux-user/ppc/syscall.h
@@ -62,3 +62,5 @@ struct target_revectored_struct {
#else
#define UNAME_MACHINE "ppc"
#endif
+
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 6569608b64..4a16e8fe1d 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -16,16 +16,10 @@
#include "exec/user/thunk.h"
#include "syscall_defs.h"
#include "syscall.h"
-#include "target_cpu.h"
-#include "target_signal.h"
#include "exec/gdbstub.h"
#include "qemu/queue.h"
-#if defined(CONFIG_USE_NPTL)
#define THREAD __thread
-#else
-#define THREAD
-#endif
/* This struct is used to hold certain information about the image.
* Basically, it replicates in user space what would be certain
@@ -118,11 +112,10 @@ typedef struct TaskState {
uint32_t v86flags;
uint32_t v86mask;
#endif
-#ifdef CONFIG_USE_NPTL
abi_ulong child_tidptr;
-#endif
#ifdef TARGET_M68K
int sim_syscalls;
+ abi_ulong tp_value;
#endif
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
/* Extra fields for semihosted binaries. */
@@ -269,10 +262,8 @@ void mmap_unlock(void);
abi_ulong mmap_find_vma(abi_ulong, abi_ulong);
void cpu_list_lock(void);
void cpu_list_unlock(void);
-#if defined(CONFIG_USE_NPTL)
void mmap_fork_start(void);
void mmap_fork_end(int child);
-#endif
/* main.c */
extern unsigned long guest_stack_size;
@@ -450,8 +441,13 @@ static inline void *lock_user_string(abi_ulong guest_addr)
#define unlock_user_struct(host_ptr, guest_addr, copy) \
unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
-#if defined(CONFIG_USE_NPTL)
#include <pthread.h>
-#endif
+
+/* Include target-specific struct and function definitions;
+ * they may need access to the target-independent structures
+ * above, so include them last.
+ */
+#include "target_cpu.h"
+#include "target_signal.h"
#endif /* QEMU_H */
diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h
index e4603b79c3..ea8c304840 100644
--- a/linux-user/s390x/syscall.h
+++ b/linux-user/s390x/syscall.h
@@ -21,3 +21,5 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "s390x"
+
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/signal.c b/linux-user/signal.c
index d0727becc2..a5e8906c4d 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -5386,6 +5386,7 @@ long do_rt_sigreturn(CPUArchState *env)
void process_pending_signals(CPUArchState *cpu_env)
{
+ CPUState *cpu = ENV_GET_CPU(cpu_env);
int sig;
abi_ulong handler;
sigset_t set, old_set;
@@ -5419,7 +5420,7 @@ void process_pending_signals(CPUArchState *cpu_env)
if (!k->first)
k->pending = 0;
- sig = gdb_handlesig (cpu_env, sig);
+ sig = gdb_handlesig(cpu, sig);
if (!sig) {
sa = NULL;
handler = TARGET_SIG_IGN;
diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h
index 5a9bb7e546..4cd64bf41d 100644
--- a/linux-user/sparc/syscall.h
+++ b/linux-user/sparc/syscall.h
@@ -7,3 +7,10 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "sun4"
+
+/* SPARC kernels don't define this in their Kconfig, but they have the
+ * same ABI as if they did, implemented by sparc-specific code which fishes
+ * directly in the u_regs() struct for half the parameters in sparc_do_fork()
+ * and copy_thread().
+ */
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h
index 5a620a2bb7..4944d465a2 100644
--- a/linux-user/sparc/target_cpu.h
+++ b/linux-user/sparc/target_cpu.h
@@ -25,12 +25,20 @@ static inline void cpu_clone_regs(CPUSPARCState *env, target_ulong newsp)
if (newsp) {
env->regwptr[22] = newsp;
}
+ /* syscall return for clone child: 0, and clear CF since
+ * this counts as a success return value.
+ */
env->regwptr[0] = 0;
- /* FIXME: Do we also need to clear CF? */
- /* XXXXX */
- printf("HELPME: %s:%d\n", __FILE__, __LINE__);
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ env->xcc &= ~PSR_CARRY;
+#else
+ env->psr &= ~PSR_CARRY;
+#endif
}
-/* TODO: need to implement cpu_set_tls() */
+static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls)
+{
+ env->gregs[7] = newtls;
+}
#endif
diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h
index 81a816de94..e60bf311c0 100644
--- a/linux-user/sparc64/syscall.h
+++ b/linux-user/sparc64/syscall.h
@@ -8,3 +8,10 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "sun4u"
+
+/* SPARC kernels don't define this in their Kconfig, but they have the
+ * same ABI as if they did, implemented by sparc-specific code which fishes
+ * directly in the u_regs() struct for half the parameters in sparc_do_fork()
+ * and copy_thread().
+ */
+#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 00a0390ea9..3f6db4b0d1 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -111,13 +111,8 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include "qemu.h"
-#if defined(CONFIG_USE_NPTL)
#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
-#else
-/* XXX: Hardcode the above values. */
-#define CLONE_NPTL_FLAGS2 0
-#endif
//#define DEBUG
@@ -234,12 +229,10 @@ _syscall1(int,exit_group,int,error_code)
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
_syscall1(int,set_tid_address,int *,tidptr)
#endif
-#if defined(CONFIG_USE_NPTL)
#if defined(TARGET_NR_futex) && defined(__NR_futex)
_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
const struct timespec *,timeout,int *,uaddr2,int,val3)
#endif
-#endif
#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr);
@@ -1039,6 +1032,9 @@ static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
#elif defined(TARGET_SH4)
((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
return host_pipe[0];
+#elif defined(TARGET_SPARC)
+ ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
+ return host_pipe[0];
#endif
}
@@ -4055,7 +4051,7 @@ static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
}
#if defined(TARGET_I386) && defined(TARGET_ABI32)
-static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
+abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
{
uint64_t *gdt_table = g2h(env->gdt.base);
struct target_modify_ldt_ldt_s ldt_info;
@@ -4189,7 +4185,7 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
#endif /* TARGET_I386 && TARGET_ABI32 */
#ifndef TARGET_ABI32
-static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
+abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
{
abi_long ret = 0;
abi_ulong val;
@@ -4227,7 +4223,6 @@ static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
#define NEW_STACK_SIZE 0x40000
-#if defined(CONFIG_USE_NPTL)
static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct {
@@ -4272,16 +4267,6 @@ static void *clone_func(void *arg)
/* never exits */
return NULL;
}
-#else
-
-static int clone_func(void *arg)
-{
- CPUArchState *env = arg;
- cpu_loop(env);
- /* never exits */
- return 0;
-}
-#endif
/* do_fork() Must return host values and target errnos (unlike most
do_*() functions). */
@@ -4292,12 +4277,8 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
int ret;
TaskState *ts;
CPUArchState *new_env;
-#if defined(CONFIG_USE_NPTL)
unsigned int nptl_flags;
sigset_t sigmask;
-#else
- uint8_t *new_stack;
-#endif
/* Emulate vfork() with fork() */
if (flags & CLONE_VFORK)
@@ -4305,23 +4286,18 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
if (flags & CLONE_VM) {
TaskState *parent_ts = (TaskState *)env->opaque;
-#if defined(CONFIG_USE_NPTL)
new_thread_info info;
pthread_attr_t attr;
-#endif
+
ts = g_malloc0(sizeof(TaskState));
init_task_state(ts);
/* we create a new CPU instance. */
new_env = cpu_copy(env);
-#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
- cpu_reset(ENV_GET_CPU(new_env));
-#endif
/* Init regs that differ from the parent. */
cpu_clone_regs(new_env, newsp);
new_env->opaque = ts;
ts->bprm = parent_ts->bprm;
ts->info = parent_ts->info;
-#if defined(CONFIG_USE_NPTL)
nptl_flags = flags;
flags &= ~CLONE_NPTL_FLAGS2;
@@ -4371,17 +4347,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pthread_cond_destroy(&info.cond);
pthread_mutex_destroy(&info.mutex);
pthread_mutex_unlock(&clone_lock);
-#else
- if (flags & CLONE_NPTL_FLAGS2)
- return -EINVAL;
- /* This is probably going to die very quickly, but do it anyway. */
- new_stack = g_malloc0 (NEW_STACK_SIZE);
-#ifdef __ia64__
- ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
-#else
- ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
-#endif
-#endif
} else {
/* if no CLONE_VM, we consider it is a fork */
if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
@@ -4392,7 +4357,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
/* Child Process. */
cpu_clone_regs(env, newsp);
fork_end(1);
-#if defined(CONFIG_USE_NPTL)
/* There is a race condition here. The parent process could
theoretically read the TID in the child process before the child
tid is set. This would require using either ptrace
@@ -4408,7 +4372,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
cpu_set_tls (env, newtls);
if (flags & CLONE_CHILD_CLEARTID)
ts->child_tidptr = child_tidptr;
-#endif
} else {
fork_end(0);
}
@@ -4834,7 +4797,6 @@ static inline abi_long host_to_target_stat64(void *cpu_env,
}
#endif
-#if defined(CONFIG_USE_NPTL)
/* ??? Using host futex calls even when target atomic operations
are not really atomic probably breaks things. However implementing
futexes locally would make futexes shared between multiple processes
@@ -4886,7 +4848,6 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
return -TARGET_ENOSYS;
}
}
-#endif
/* Map host to target signal numbers for the wait family of syscalls.
Assume all other status bits are the same. */
@@ -5132,9 +5093,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg5, abi_long arg6, abi_long arg7,
abi_long arg8)
{
-#ifdef CONFIG_USE_NPTL
CPUState *cpu = ENV_GET_CPU(cpu_env);
-#endif
abi_long ret;
struct stat st;
struct statfs stfs;
@@ -5148,7 +5107,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
switch(num) {
case TARGET_NR_exit:
-#ifdef CONFIG_USE_NPTL
/* In old applications this may be used to implement _exit(2).
However in threaded applictions it is used for thread termination,
and _exit_group is used for application termination.
@@ -5186,7 +5144,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
g_free(ts);
pthread_exit(NULL);
}
-#endif
#ifdef TARGET_GPROF
_mcleanup();
#endif
@@ -6956,16 +6913,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(fsync(arg1));
break;
case TARGET_NR_clone:
-#if defined(TARGET_SH4) || defined(TARGET_ALPHA)
- ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
-#elif defined(TARGET_CRIS)
- ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
-#elif defined(TARGET_MICROBLAZE)
+ /* Linux manages to have three different orderings for its
+ * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
+ * match the kernel's CONFIG_CLONE_* settings.
+ * Microblaze is further special in that it uses a sixth
+ * implicit argument to clone for the TLS pointer.
+ */
+#if defined(TARGET_MICROBLAZE)
ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
-#elif defined(TARGET_S390X)
+#elif defined(TARGET_CLONE_BACKWARDS)
+ ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
+#elif defined(TARGET_CLONE_BACKWARDS2)
ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
#else
- ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
+ ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
#endif
break;
#ifdef __NR_exit_group
@@ -8558,6 +8519,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
ret = do_set_thread_area(cpu_env, arg1);
break;
+#elif defined(TARGET_M68K)
+ {
+ TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+ ts->tp_value = arg1;
+ break;
+ }
#else
goto unimplemented_nowarn;
#endif
@@ -8566,6 +8533,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_get_thread_area:
#if defined(TARGET_I386) && defined(TARGET_ABI32)
ret = do_get_thread_area(cpu_env, arg1);
+ break;
+#elif defined(TARGET_M68K)
+ {
+ TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+ ret = ts->tp_value;
+ break;
+ }
#else
goto unimplemented_nowarn;
#endif
@@ -8670,11 +8644,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
break;
#endif
-#if defined(CONFIG_USE_NPTL)
case TARGET_NR_futex:
ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
break;
-#endif
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
case TARGET_NR_inotify_init:
ret = get_errno(sys_inotify_init());
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 92c01a9603..086fbfffe7 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1138,8 +1138,7 @@ struct target_winsize {
#endif
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) \
- || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) \
- || defined(TARGET_OPENRISC)
+ || defined(TARGET_CRIS) || defined(TARGET_UNICORE32)
struct target_stat {
unsigned short st_dev;
unsigned short __pad1;
@@ -1837,29 +1836,55 @@ struct target_stat {
abi_ulong __unused[3];
};
#elif defined(TARGET_OPENRISC)
+
+/* These are the asm-generic versions of the stat and stat64 structures */
+
struct target_stat {
abi_ulong st_dev;
abi_ulong st_ino;
- abi_ulong st_nlink;
-
unsigned int st_mode;
+ unsigned int st_nlink;
unsigned int st_uid;
unsigned int st_gid;
- unsigned int __pad0;
abi_ulong st_rdev;
+ abi_ulong __pad1;
abi_long st_size;
- abi_long st_blksize;
- abi_long st_blocks; /* Number 512-byte blocks allocated. */
-
- abi_ulong target_st_atime;
+ int st_blksize;
+ int __pad2;
+ abi_long st_blocks;
+ abi_long target_st_atime;
abi_ulong target_st_atime_nsec;
- abi_ulong target_st_mtime;
+ abi_long target_st_mtime;
abi_ulong target_st_mtime_nsec;
- abi_ulong target_st_ctime;
+ abi_long target_st_ctime;
abi_ulong target_st_ctime_nsec;
+ unsigned int __unused4;
+ unsigned int __unused5;
+};
- abi_long __unused[3];
+struct target_stat64 {
+ uint64_t st_dev;
+ uint64_t st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ uint64_t st_rdev;
+ uint64_t __pad1;
+ int64_t st_size;
+ int st_blksize;
+ int __pad2;
+ int64_t st_blocks;
+ int target_st_atime;
+ unsigned int target_st_atime_nsec;
+ int target_st_mtime;
+ unsigned int target_st_mtime_nsec;
+ int target_st_ctime;
+ unsigned int target_st_ctime_nsec;
+ unsigned int __unused4;
+ unsigned int __unused5;
};
+
#else
#error unsupported CPU
#endif
@@ -2434,8 +2459,11 @@ typedef union target_epoll_data {
struct target_epoll_event {
uint32_t events;
+#ifdef TARGET_ARM
+ uint32_t __pad;
+#endif
target_epoll_data_t data;
-};
+} QEMU_PACKED;
#endif
struct target_rlimit64 {
uint64_t rlim_cur;
diff --git a/memory.c b/memory.c
index c8f9a2bfb3..1494e955d4 100644
--- a/memory.c
+++ b/memory.c
@@ -339,28 +339,65 @@ static void flatview_simplify(FlatView *view)
}
}
-static void memory_region_oldmmio_read_accessor(void *opaque,
+static bool memory_region_big_endian(MemoryRegion *mr)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ return mr->ops->endianness != DEVICE_LITTLE_ENDIAN;
+#else
+ return mr->ops->endianness == DEVICE_BIG_ENDIAN;
+#endif
+}
+
+static bool memory_region_wrong_endianness(MemoryRegion *mr)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ return mr->ops->endianness == DEVICE_LITTLE_ENDIAN;
+#else
+ return mr->ops->endianness == DEVICE_BIG_ENDIAN;
+#endif
+}
+
+static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size)
+{
+ if (memory_region_wrong_endianness(mr)) {
+ switch (size) {
+ case 1:
+ break;
+ case 2:
+ *data = bswap16(*data);
+ break;
+ case 4:
+ *data = bswap32(*data);
+ break;
+ case 8:
+ *data = bswap64(*data);
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
+static void memory_region_oldmmio_read_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
uint64_t mask)
{
- MemoryRegion *mr = opaque;
uint64_t tmp;
tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
*value |= (tmp & mask) << shift;
}
-static void memory_region_read_accessor(void *opaque,
+static void memory_region_read_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
uint64_t mask)
{
- MemoryRegion *mr = opaque;
uint64_t tmp;
if (mr->flush_coalesced_mmio) {
@@ -370,28 +407,26 @@ static void memory_region_read_accessor(void *opaque,
*value |= (tmp & mask) << shift;
}
-static void memory_region_oldmmio_write_accessor(void *opaque,
+static void memory_region_oldmmio_write_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
uint64_t mask)
{
- MemoryRegion *mr = opaque;
uint64_t tmp;
tmp = (*value >> shift) & mask;
mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, tmp);
}
-static void memory_region_write_accessor(void *opaque,
+static void memory_region_write_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
uint64_t mask)
{
- MemoryRegion *mr = opaque;
uint64_t tmp;
if (mr->flush_coalesced_mmio) {
@@ -406,13 +441,13 @@ static void access_with_adjusted_size(hwaddr addr,
unsigned size,
unsigned access_size_min,
unsigned access_size_max,
- void (*access)(void *opaque,
+ void (*access)(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
uint64_t mask),
- void *opaque)
+ MemoryRegion *mr)
{
uint64_t access_mask;
unsigned access_size;
@@ -428,13 +463,15 @@ static void access_with_adjusted_size(hwaddr addr,
/* FIXME: support unaligned access? */
access_size = MAX(MIN(size, access_size_max), access_size_min);
access_mask = -1ULL >> (64 - access_size * 8);
- for (i = 0; i < size; i += access_size) {
-#ifdef TARGET_WORDS_BIGENDIAN
- access(opaque, addr + i, value, access_size,
- (size - access_size - i) * 8, access_mask);
-#else
- access(opaque, addr + i, value, access_size, i * 8, access_mask);
-#endif
+ if (memory_region_big_endian(mr)) {
+ for (i = 0; i < size; i += access_size) {
+ access(mr, addr + i, value, access_size,
+ (size - access_size - i) * 8, access_mask);
+ }
+ } else {
+ for (i = 0; i < size; i += access_size) {
+ access(mr, addr + i, value, access_size, i * 8, access_mask);
+ }
}
}
@@ -786,15 +823,6 @@ static void memory_region_destructor_rom_device(MemoryRegion *mr)
qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK);
}
-static bool memory_region_wrong_endianness(MemoryRegion *mr)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- return mr->ops->endianness == DEVICE_LITTLE_ENDIAN;
-#else
- return mr->ops->endianness == DEVICE_BIG_ENDIAN;
-#endif
-}
-
void memory_region_init(MemoryRegion *mr,
Object *owner,
const char *name,
@@ -805,7 +833,6 @@ void memory_region_init(MemoryRegion *mr,
mr->owner = owner;
mr->iommu_ops = NULL;
mr->parent = NULL;
- mr->owner = NULL;
mr->size = int128_make64(size);
if (size == UINT64_MAX) {
mr->size = int128_2_64();
@@ -841,7 +868,7 @@ static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
if (current_cpu != NULL) {
cpu_unassigned_access(current_cpu, addr, false, false, 0, size);
}
- return 0;
+ return -1ULL;
}
static void unassigned_mem_write(void *opaque, hwaddr addr,
@@ -922,27 +949,6 @@ static uint64_t memory_region_dispatch_read1(MemoryRegion *mr,
return data;
}
-static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size)
-{
- if (memory_region_wrong_endianness(mr)) {
- switch (size) {
- case 1:
- break;
- case 2:
- *data = bswap16(*data);
- break;
- case 4:
- *data = bswap32(*data);
- break;
- case 8:
- *data = bswap64(*data);
- break;
- default:
- abort();
- }
- }
-}
-
static bool memory_region_dispatch_read(MemoryRegion *mr,
hwaddr addr,
uint64_t *pval,
@@ -1788,7 +1794,9 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
"-" TARGET_FMT_plx "\n",
base + mr->addr,
base + mr->addr
- + (hwaddr)int128_get64(int128_sub(mr->size, int128_make64(1))),
+ + (int128_nz(mr->size) ?
+ (hwaddr)int128_get64(int128_sub(mr->size,
+ int128_one())) : 0),
mr->priority,
mr->romd_mode ? 'R' : '-',
!mr->readonly && !(mr->rom_device && mr->romd_mode) ? 'W'
@@ -1803,7 +1811,9 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %c%c): %s\n",
base + mr->addr,
base + mr->addr
- + (hwaddr)int128_get64(int128_sub(mr->size, int128_make64(1))),
+ + (int128_nz(mr->size) ?
+ (hwaddr)int128_get64(int128_sub(mr->size,
+ int128_one())) : 0),
mr->priority,
mr->romd_mode ? 'R' : '-',
!mr->readonly && !(mr->rom_device && mr->romd_mode) ? 'W'
diff --git a/migration-rdma.c b/migration-rdma.c
new file mode 100644
index 0000000000..d044830ed8
--- /dev/null
+++ b/migration-rdma.c
@@ -0,0 +1,3249 @@
+/*
+ * RDMA protocol and interfaces
+ *
+ * Copyright IBM, Corp. 2010-2013
+ *
+ * Authors:
+ * Michael R. Hines <mrhines@us.ibm.com>
+ * Jiuxing Liu <jl@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu-common.h"
+#include "migration/migration.h"
+#include "migration/qemu-file.h"
+#include "exec/cpu-common.h"
+#include "qemu/main-loop.h"
+#include "qemu/sockets.h"
+#include "qemu/bitmap.h"
+#include "block/coroutine.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <rdma/rdma_cma.h>
+
+#define DEBUG_RDMA
+//#define DEBUG_RDMA_VERBOSE
+//#define DEBUG_RDMA_REALLY_VERBOSE
+
+#ifdef DEBUG_RDMA
+#define DPRINTF(fmt, ...) \
+ do { printf("rdma: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+ do { } while (0)
+#endif
+
+#ifdef DEBUG_RDMA_VERBOSE
+#define DDPRINTF(fmt, ...) \
+ do { printf("rdma: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DDPRINTF(fmt, ...) \
+ do { } while (0)
+#endif
+
+#ifdef DEBUG_RDMA_REALLY_VERBOSE
+#define DDDPRINTF(fmt, ...) \
+ do { printf("rdma: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DDDPRINTF(fmt, ...) \
+ do { } while (0)
+#endif
+
+/*
+ * Print and error on both the Monitor and the Log file.
+ */
+#define ERROR(errp, fmt, ...) \
+ do { \
+ fprintf(stderr, "RDMA ERROR: " fmt, ## __VA_ARGS__); \
+ if (errp && (*(errp) == NULL)) { \
+ error_setg(errp, "RDMA ERROR: " fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define RDMA_RESOLVE_TIMEOUT_MS 10000
+
+/* Do not merge data if larger than this. */
+#define RDMA_MERGE_MAX (2 * 1024 * 1024)
+#define RDMA_SIGNALED_SEND_MAX (RDMA_MERGE_MAX / 4096)
+
+#define RDMA_REG_CHUNK_SHIFT 20 /* 1 MB */
+
+/*
+ * This is only for non-live state being migrated.
+ * Instead of RDMA_WRITE messages, we use RDMA_SEND
+ * messages for that state, which requires a different
+ * delivery design than main memory.
+ */
+#define RDMA_SEND_INCREMENT 32768
+
+/*
+ * Maximum size infiniband SEND message
+ */
+#define RDMA_CONTROL_MAX_BUFFER (512 * 1024)
+#define RDMA_CONTROL_MAX_COMMANDS_PER_MESSAGE 4096
+
+#define RDMA_CONTROL_VERSION_CURRENT 1
+/*
+ * Capabilities for negotiation.
+ */
+#define RDMA_CAPABILITY_PIN_ALL 0x01
+
+/*
+ * Add the other flags above to this list of known capabilities
+ * as they are introduced.
+ */
+static uint32_t known_capabilities = RDMA_CAPABILITY_PIN_ALL;
+
+#define CHECK_ERROR_STATE() \
+ do { \
+ if (rdma->error_state) { \
+ if (!rdma->error_reported) { \
+ fprintf(stderr, "RDMA is in an error state waiting migration" \
+ " to abort!\n"); \
+ rdma->error_reported = 1; \
+ } \
+ return rdma->error_state; \
+ } \
+ } while (0);
+
+/*
+ * A work request ID is 64-bits and we split up these bits
+ * into 3 parts:
+ *
+ * bits 0-15 : type of control message, 2^16
+ * bits 16-29: ram block index, 2^14
+ * bits 30-63: ram block chunk number, 2^34
+ *
+ * The last two bit ranges are only used for RDMA writes,
+ * in order to track their completion and potentially
+ * also track unregistration status of the message.
+ */
+#define RDMA_WRID_TYPE_SHIFT 0UL
+#define RDMA_WRID_BLOCK_SHIFT 16UL
+#define RDMA_WRID_CHUNK_SHIFT 30UL
+
+#define RDMA_WRID_TYPE_MASK \
+ ((1UL << RDMA_WRID_BLOCK_SHIFT) - 1UL)
+
+#define RDMA_WRID_BLOCK_MASK \
+ (~RDMA_WRID_TYPE_MASK & ((1UL << RDMA_WRID_CHUNK_SHIFT) - 1UL))
+
+#define RDMA_WRID_CHUNK_MASK (~RDMA_WRID_BLOCK_MASK & ~RDMA_WRID_TYPE_MASK)
+
+/*
+ * RDMA migration protocol:
+ * 1. RDMA Writes (data messages, i.e. RAM)
+ * 2. IB Send/Recv (control channel messages)
+ */
+enum {
+ RDMA_WRID_NONE = 0,
+ RDMA_WRID_RDMA_WRITE = 1,
+ RDMA_WRID_SEND_CONTROL = 2000,
+ RDMA_WRID_RECV_CONTROL = 4000,
+};
+
+const char *wrid_desc[] = {
+ [RDMA_WRID_NONE] = "NONE",
+ [RDMA_WRID_RDMA_WRITE] = "WRITE RDMA",
+ [RDMA_WRID_SEND_CONTROL] = "CONTROL SEND",
+ [RDMA_WRID_RECV_CONTROL] = "CONTROL RECV",
+};
+
+/*
+ * Work request IDs for IB SEND messages only (not RDMA writes).
+ * This is used by the migration protocol to transmit
+ * control messages (such as device state and registration commands)
+ *
+ * We could use more WRs, but we have enough for now.
+ */
+enum {
+ RDMA_WRID_READY = 0,
+ RDMA_WRID_DATA,
+ RDMA_WRID_CONTROL,
+ RDMA_WRID_MAX,
+};
+
+/*
+ * SEND/RECV IB Control Messages.
+ */
+enum {
+ RDMA_CONTROL_NONE = 0,
+ RDMA_CONTROL_ERROR,
+ RDMA_CONTROL_READY, /* ready to receive */
+ RDMA_CONTROL_QEMU_FILE, /* QEMUFile-transmitted bytes */
+ RDMA_CONTROL_RAM_BLOCKS_REQUEST, /* RAMBlock synchronization */
+ RDMA_CONTROL_RAM_BLOCKS_RESULT, /* RAMBlock synchronization */
+ RDMA_CONTROL_COMPRESS, /* page contains repeat values */
+ RDMA_CONTROL_REGISTER_REQUEST, /* dynamic page registration */
+ RDMA_CONTROL_REGISTER_RESULT, /* key to use after registration */
+ RDMA_CONTROL_REGISTER_FINISHED, /* current iteration finished */
+ RDMA_CONTROL_UNREGISTER_REQUEST, /* dynamic UN-registration */
+ RDMA_CONTROL_UNREGISTER_FINISHED, /* unpinning finished */
+};
+
+const char *control_desc[] = {
+ [RDMA_CONTROL_NONE] = "NONE",
+ [RDMA_CONTROL_ERROR] = "ERROR",
+ [RDMA_CONTROL_READY] = "READY",
+ [RDMA_CONTROL_QEMU_FILE] = "QEMU FILE",
+ [RDMA_CONTROL_RAM_BLOCKS_REQUEST] = "RAM BLOCKS REQUEST",
+ [RDMA_CONTROL_RAM_BLOCKS_RESULT] = "RAM BLOCKS RESULT",
+ [RDMA_CONTROL_COMPRESS] = "COMPRESS",
+ [RDMA_CONTROL_REGISTER_REQUEST] = "REGISTER REQUEST",
+ [RDMA_CONTROL_REGISTER_RESULT] = "REGISTER RESULT",
+ [RDMA_CONTROL_REGISTER_FINISHED] = "REGISTER FINISHED",
+ [RDMA_CONTROL_UNREGISTER_REQUEST] = "UNREGISTER REQUEST",
+ [RDMA_CONTROL_UNREGISTER_FINISHED] = "UNREGISTER FINISHED",
+};
+
+/*
+ * Memory and MR structures used to represent an IB Send/Recv work request.
+ * This is *not* used for RDMA writes, only IB Send/Recv.
+ */
+typedef struct {
+ uint8_t control[RDMA_CONTROL_MAX_BUFFER]; /* actual buffer to register */
+ struct ibv_mr *control_mr; /* registration metadata */
+ size_t control_len; /* length of the message */
+ uint8_t *control_curr; /* start of unconsumed bytes */
+} RDMAWorkRequestData;
+
+/*
+ * Negotiate RDMA capabilities during connection-setup time.
+ */
+typedef struct {
+ uint32_t version;
+ uint32_t flags;
+} RDMACapabilities;
+
+static void caps_to_network(RDMACapabilities *cap)
+{
+ cap->version = htonl(cap->version);
+ cap->flags = htonl(cap->flags);
+}
+
+static void network_to_caps(RDMACapabilities *cap)
+{
+ cap->version = ntohl(cap->version);
+ cap->flags = ntohl(cap->flags);
+}
+
+/*
+ * Representation of a RAMBlock from an RDMA perspective.
+ * This is not transmitted, only local.
+ * This and subsequent structures cannot be linked lists
+ * because we're using a single IB message to transmit
+ * the information. It's small anyway, so a list is overkill.
+ */
+typedef struct RDMALocalBlock {
+ uint8_t *local_host_addr; /* local virtual address */
+ uint64_t remote_host_addr; /* remote virtual address */
+ uint64_t offset;
+ uint64_t length;
+ struct ibv_mr **pmr; /* MRs for chunk-level registration */
+ struct ibv_mr *mr; /* MR for non-chunk-level registration */
+ uint32_t *remote_keys; /* rkeys for chunk-level registration */
+ uint32_t remote_rkey; /* rkeys for non-chunk-level registration */
+ int index; /* which block are we */
+ bool is_ram_block;
+ int nb_chunks;
+ unsigned long *transit_bitmap;
+ unsigned long *unregister_bitmap;
+} RDMALocalBlock;
+
+/*
+ * Also represents a RAMblock, but only on the dest.
+ * This gets transmitted by the dest during connection-time
+ * to the source VM and then is used to populate the
+ * corresponding RDMALocalBlock with
+ * the information needed to perform the actual RDMA.
+ */
+typedef struct QEMU_PACKED RDMARemoteBlock {
+ uint64_t remote_host_addr;
+ uint64_t offset;
+ uint64_t length;
+ uint32_t remote_rkey;
+ uint32_t padding;
+} RDMARemoteBlock;
+
+static uint64_t htonll(uint64_t v)
+{
+ union { uint32_t lv[2]; uint64_t llv; } u;
+ u.lv[0] = htonl(v >> 32);
+ u.lv[1] = htonl(v & 0xFFFFFFFFULL);
+ return u.llv;
+}
+
+static uint64_t ntohll(uint64_t v) {
+ union { uint32_t lv[2]; uint64_t llv; } u;
+ u.llv = v;
+ return ((uint64_t)ntohl(u.lv[0]) << 32) | (uint64_t) ntohl(u.lv[1]);
+}
+
+static void remote_block_to_network(RDMARemoteBlock *rb)
+{
+ rb->remote_host_addr = htonll(rb->remote_host_addr);
+ rb->offset = htonll(rb->offset);
+ rb->length = htonll(rb->length);
+ rb->remote_rkey = htonl(rb->remote_rkey);
+}
+
+static void network_to_remote_block(RDMARemoteBlock *rb)
+{
+ rb->remote_host_addr = ntohll(rb->remote_host_addr);
+ rb->offset = ntohll(rb->offset);
+ rb->length = ntohll(rb->length);
+ rb->remote_rkey = ntohl(rb->remote_rkey);
+}
+
+/*
+ * Virtual address of the above structures used for transmitting
+ * the RAMBlock descriptions at connection-time.
+ * This structure is *not* transmitted.
+ */
+typedef struct RDMALocalBlocks {
+ int nb_blocks;
+ bool init; /* main memory init complete */
+ RDMALocalBlock *block;
+} RDMALocalBlocks;
+
+/*
+ * Main data structure for RDMA state.
+ * While there is only one copy of this structure being allocated right now,
+ * this is the place where one would start if you wanted to consider
+ * having more than one RDMA connection open at the same time.
+ */
+typedef struct RDMAContext {
+ char *host;
+ int port;
+
+ RDMAWorkRequestData wr_data[RDMA_WRID_MAX + 1];
+
+ /*
+ * This is used by *_exchange_send() to figure out whether or not
+ * the initial "READY" message has already been received or not.
+ * This is because other functions may potentially poll() and detect
+ * the READY message before send() does, in which case we need to
+ * know if it completed.
+ */
+ int control_ready_expected;
+
+ /* number of outstanding writes */
+ int nb_sent;
+
+ /* store info about current buffer so that we can
+ merge it with future sends */
+ uint64_t current_addr;
+ uint64_t current_length;
+ /* index of ram block the current buffer belongs to */
+ int current_index;
+ /* index of the chunk in the current ram block */
+ int current_chunk;
+
+ bool pin_all;
+
+ /*
+ * infiniband-specific variables for opening the device
+ * and maintaining connection state and so forth.
+ *
+ * cm_id also has ibv_context, rdma_event_channel, and ibv_qp in
+ * cm_id->verbs, cm_id->channel, and cm_id->qp.
+ */
+ struct rdma_cm_id *cm_id; /* connection manager ID */
+ struct rdma_cm_id *listen_id;
+
+ struct ibv_context *verbs;
+ struct rdma_event_channel *channel;
+ struct ibv_qp *qp; /* queue pair */
+ struct ibv_comp_channel *comp_channel; /* completion channel */
+ struct ibv_pd *pd; /* protection domain */
+ struct ibv_cq *cq; /* completion queue */
+
+ /*
+ * If a previous write failed (perhaps because of a failed
+ * memory registration, then do not attempt any future work
+ * and remember the error state.
+ */
+ int error_state;
+ int error_reported;
+
+ /*
+ * Description of ram blocks used throughout the code.
+ */
+ RDMALocalBlocks local_ram_blocks;
+ RDMARemoteBlock *block;
+
+ /*
+ * Migration on *destination* started.
+ * Then use coroutine yield function.
+ * Source runs in a thread, so we don't care.
+ */
+ int migration_started_on_destination;
+
+ int total_registrations;
+ int total_writes;
+
+ int unregister_current, unregister_next;
+ uint64_t unregistrations[RDMA_SIGNALED_SEND_MAX];
+
+ GHashTable *blockmap;
+} RDMAContext;
+
+/*
+ * Interface to the rest of the migration call stack.
+ */
+typedef struct QEMUFileRDMA {
+ RDMAContext *rdma;
+ size_t len;
+ void *file;
+} QEMUFileRDMA;
+
+/*
+ * Main structure for IB Send/Recv control messages.
+ * This gets prepended at the beginning of every Send/Recv.
+ */
+typedef struct QEMU_PACKED {
+ uint32_t len; /* Total length of data portion */
+ uint32_t type; /* which control command to perform */
+ uint32_t repeat; /* number of commands in data portion of same type */
+ uint32_t padding;
+} RDMAControlHeader;
+
+static void control_to_network(RDMAControlHeader *control)
+{
+ control->type = htonl(control->type);
+ control->len = htonl(control->len);
+ control->repeat = htonl(control->repeat);
+}
+
+static void network_to_control(RDMAControlHeader *control)
+{
+ control->type = ntohl(control->type);
+ control->len = ntohl(control->len);
+ control->repeat = ntohl(control->repeat);
+}
+
+/*
+ * Register a single Chunk.
+ * Information sent by the source VM to inform the dest
+ * to register an single chunk of memory before we can perform
+ * the actual RDMA operation.
+ */
+typedef struct QEMU_PACKED {
+ union QEMU_PACKED {
+ uint64_t current_addr; /* offset into the ramblock of the chunk */
+ uint64_t chunk; /* chunk to lookup if unregistering */
+ } key;
+ uint32_t current_index; /* which ramblock the chunk belongs to */
+ uint32_t padding;
+ uint64_t chunks; /* how many sequential chunks to register */
+} RDMARegister;
+
+static void register_to_network(RDMARegister *reg)
+{
+ reg->key.current_addr = htonll(reg->key.current_addr);
+ reg->current_index = htonl(reg->current_index);
+ reg->chunks = htonll(reg->chunks);
+}
+
+static void network_to_register(RDMARegister *reg)
+{
+ reg->key.current_addr = ntohll(reg->key.current_addr);
+ reg->current_index = ntohl(reg->current_index);
+ reg->chunks = ntohll(reg->chunks);
+}
+
+typedef struct QEMU_PACKED {
+ uint32_t value; /* if zero, we will madvise() */
+ uint32_t block_idx; /* which ram block index */
+ uint64_t offset; /* where in the remote ramblock this chunk */
+ uint64_t length; /* length of the chunk */
+} RDMACompress;
+
+static void compress_to_network(RDMACompress *comp)
+{
+ comp->value = htonl(comp->value);
+ comp->block_idx = htonl(comp->block_idx);
+ comp->offset = htonll(comp->offset);
+ comp->length = htonll(comp->length);
+}
+
+static void network_to_compress(RDMACompress *comp)
+{
+ comp->value = ntohl(comp->value);
+ comp->block_idx = ntohl(comp->block_idx);
+ comp->offset = ntohll(comp->offset);
+ comp->length = ntohll(comp->length);
+}
+
+/*
+ * The result of the dest's memory registration produces an "rkey"
+ * which the source VM must reference in order to perform
+ * the RDMA operation.
+ */
+typedef struct QEMU_PACKED {
+ uint32_t rkey;
+ uint32_t padding;
+ uint64_t host_addr;
+} RDMARegisterResult;
+
+static void result_to_network(RDMARegisterResult *result)
+{
+ result->rkey = htonl(result->rkey);
+ result->host_addr = htonll(result->host_addr);
+};
+
+static void network_to_result(RDMARegisterResult *result)
+{
+ result->rkey = ntohl(result->rkey);
+ result->host_addr = ntohll(result->host_addr);
+};
+
+const char *print_wrid(int wrid);
+static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head,
+ uint8_t *data, RDMAControlHeader *resp,
+ int *resp_idx,
+ int (*callback)(RDMAContext *rdma));
+
+static inline uint64_t ram_chunk_index(uint8_t *start, uint8_t *host)
+{
+ return ((uintptr_t) host - (uintptr_t) start) >> RDMA_REG_CHUNK_SHIFT;
+}
+
+static inline uint8_t *ram_chunk_start(RDMALocalBlock *rdma_ram_block,
+ uint64_t i)
+{
+ return (uint8_t *) (((uintptr_t) rdma_ram_block->local_host_addr)
+ + (i << RDMA_REG_CHUNK_SHIFT));
+}
+
+static inline uint8_t *ram_chunk_end(RDMALocalBlock *rdma_ram_block, uint64_t i)
+{
+ uint8_t *result = ram_chunk_start(rdma_ram_block, i) +
+ (1UL << RDMA_REG_CHUNK_SHIFT);
+
+ if (result > (rdma_ram_block->local_host_addr + rdma_ram_block->length)) {
+ result = rdma_ram_block->local_host_addr + rdma_ram_block->length;
+ }
+
+ return result;
+}
+
+static int __qemu_rdma_add_block(RDMAContext *rdma, void *host_addr,
+ ram_addr_t block_offset, uint64_t length)
+{
+ RDMALocalBlocks *local = &rdma->local_ram_blocks;
+ RDMALocalBlock *block = g_hash_table_lookup(rdma->blockmap,
+ (void *) block_offset);
+ RDMALocalBlock *old = local->block;
+
+ assert(block == NULL);
+
+ local->block = g_malloc0(sizeof(RDMALocalBlock) * (local->nb_blocks + 1));
+
+ if (local->nb_blocks) {
+ int x;
+
+ for (x = 0; x < local->nb_blocks; x++) {
+ g_hash_table_remove(rdma->blockmap, (void *)old[x].offset);
+ g_hash_table_insert(rdma->blockmap, (void *)old[x].offset,
+ &local->block[x]);
+ }
+ memcpy(local->block, old, sizeof(RDMALocalBlock) * local->nb_blocks);
+ g_free(old);
+ }
+
+ block = &local->block[local->nb_blocks];
+
+ block->local_host_addr = host_addr;
+ block->offset = block_offset;
+ block->length = length;
+ block->index = local->nb_blocks;
+ block->nb_chunks = ram_chunk_index(host_addr, host_addr + length) + 1UL;
+ block->transit_bitmap = bitmap_new(block->nb_chunks);
+ bitmap_clear(block->transit_bitmap, 0, block->nb_chunks);
+ block->unregister_bitmap = bitmap_new(block->nb_chunks);
+ bitmap_clear(block->unregister_bitmap, 0, block->nb_chunks);
+ block->remote_keys = g_malloc0(block->nb_chunks * sizeof(uint32_t));
+
+ block->is_ram_block = local->init ? false : true;
+
+ g_hash_table_insert(rdma->blockmap, (void *) block_offset, block);
+
+ DDPRINTF("Added Block: %d, addr: %" PRIu64 ", offset: %" PRIu64
+ " length: %" PRIu64 " end: %" PRIu64 " bits %" PRIu64 " chunks %d\n",
+ local->nb_blocks, (uint64_t) block->local_host_addr, block->offset,
+ block->length, (uint64_t) (block->local_host_addr + block->length),
+ BITS_TO_LONGS(block->nb_chunks) *
+ sizeof(unsigned long) * 8, block->nb_chunks);
+
+ local->nb_blocks++;
+
+ return 0;
+}
+
+/*
+ * Memory regions need to be registered with the device and queue pairs setup
+ * in advanced before the migration starts. This tells us where the RAM blocks
+ * are so that we can register them individually.
+ */
+static void qemu_rdma_init_one_block(void *host_addr,
+ ram_addr_t block_offset, ram_addr_t length, void *opaque)
+{
+ __qemu_rdma_add_block(opaque, host_addr, block_offset, length);
+}
+
+/*
+ * Identify the RAMBlocks and their quantity. They will be references to
+ * identify chunk boundaries inside each RAMBlock and also be referenced
+ * during dynamic page registration.
+ */
+static int qemu_rdma_init_ram_blocks(RDMAContext *rdma)
+{
+ RDMALocalBlocks *local = &rdma->local_ram_blocks;
+
+ assert(rdma->blockmap == NULL);
+ rdma->blockmap = g_hash_table_new(g_direct_hash, g_direct_equal);
+ memset(local, 0, sizeof *local);
+ qemu_ram_foreach_block(qemu_rdma_init_one_block, rdma);
+ DPRINTF("Allocated %d local ram block structures\n", local->nb_blocks);
+ rdma->block = (RDMARemoteBlock *) g_malloc0(sizeof(RDMARemoteBlock) *
+ rdma->local_ram_blocks.nb_blocks);
+ local->init = true;
+ return 0;
+}
+
+static int __qemu_rdma_delete_block(RDMAContext *rdma, ram_addr_t block_offset)
+{
+ RDMALocalBlocks *local = &rdma->local_ram_blocks;
+ RDMALocalBlock *block = g_hash_table_lookup(rdma->blockmap,
+ (void *) block_offset);
+ RDMALocalBlock *old = local->block;
+ int x;
+
+ assert(block);
+
+ if (block->pmr) {
+ int j;
+
+ for (j = 0; j < block->nb_chunks; j++) {
+ if (!block->pmr[j]) {
+ continue;
+ }
+ ibv_dereg_mr(block->pmr[j]);
+ rdma->total_registrations--;
+ }
+ g_free(block->pmr);
+ block->pmr = NULL;
+ }
+
+ if (block->mr) {
+ ibv_dereg_mr(block->mr);
+ rdma->total_registrations--;
+ block->mr = NULL;
+ }
+
+ g_free(block->transit_bitmap);
+ block->transit_bitmap = NULL;
+
+ g_free(block->unregister_bitmap);
+ block->unregister_bitmap = NULL;
+
+ g_free(block->remote_keys);
+ block->remote_keys = NULL;
+
+ for (x = 0; x < local->nb_blocks; x++) {
+ g_hash_table_remove(rdma->blockmap, (void *)old[x].offset);
+ }
+
+ if (local->nb_blocks > 1) {
+
+ local->block = g_malloc0(sizeof(RDMALocalBlock) *
+ (local->nb_blocks - 1));
+
+ if (block->index) {
+ memcpy(local->block, old, sizeof(RDMALocalBlock) * block->index);
+ }
+
+ if (block->index < (local->nb_blocks - 1)) {
+ memcpy(local->block + block->index, old + (block->index + 1),
+ sizeof(RDMALocalBlock) *
+ (local->nb_blocks - (block->index + 1)));
+ }
+ } else {
+ assert(block == local->block);
+ local->block = NULL;
+ }
+
+ DDPRINTF("Deleted Block: %d, addr: %" PRIu64 ", offset: %" PRIu64
+ " length: %" PRIu64 " end: %" PRIu64 " bits %" PRIu64 " chunks %d\n",
+ local->nb_blocks, (uint64_t) block->local_host_addr, block->offset,
+ block->length, (uint64_t) (block->local_host_addr + block->length),
+ BITS_TO_LONGS(block->nb_chunks) *
+ sizeof(unsigned long) * 8, block->nb_chunks);
+
+ g_free(old);
+
+ local->nb_blocks--;
+
+ if (local->nb_blocks) {
+ for (x = 0; x < local->nb_blocks; x++) {
+ g_hash_table_insert(rdma->blockmap, (void *)local->block[x].offset,
+ &local->block[x]);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Put in the log file which RDMA device was opened and the details
+ * associated with that device.
+ */
+static void qemu_rdma_dump_id(const char *who, struct ibv_context *verbs)
+{
+ printf("%s RDMA Device opened: kernel name %s "
+ "uverbs device name %s, "
+ "infiniband_verbs class device path %s,"
+ " infiniband class device path %s\n",
+ who,
+ verbs->device->name,
+ verbs->device->dev_name,
+ verbs->device->dev_path,
+ verbs->device->ibdev_path);
+}
+
+/*
+ * Put in the log file the RDMA gid addressing information,
+ * useful for folks who have trouble understanding the
+ * RDMA device hierarchy in the kernel.
+ */
+static void qemu_rdma_dump_gid(const char *who, struct rdma_cm_id *id)
+{
+ char sgid[33];
+ char dgid[33];
+ inet_ntop(AF_INET6, &id->route.addr.addr.ibaddr.sgid, sgid, sizeof sgid);
+ inet_ntop(AF_INET6, &id->route.addr.addr.ibaddr.dgid, dgid, sizeof dgid);
+ DPRINTF("%s Source GID: %s, Dest GID: %s\n", who, sgid, dgid);
+}
+
+/*
+ * Figure out which RDMA device corresponds to the requested IP hostname
+ * Also create the initial connection manager identifiers for opening
+ * the connection.
+ */
+static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp)
+{
+ int ret;
+ struct addrinfo *res;
+ char port_str[16];
+ struct rdma_cm_event *cm_event;
+ char ip[40] = "unknown";
+
+ if (rdma->host == NULL || !strcmp(rdma->host, "")) {
+ ERROR(errp, "RDMA hostname has not been set\n");
+ return -1;
+ }
+
+ /* create CM channel */
+ rdma->channel = rdma_create_event_channel();
+ if (!rdma->channel) {
+ ERROR(errp, "could not create CM channel\n");
+ return -1;
+ }
+
+ /* create CM id */
+ ret = rdma_create_id(rdma->channel, &rdma->cm_id, NULL, RDMA_PS_TCP);
+ if (ret) {
+ ERROR(errp, "could not create channel id\n");
+ goto err_resolve_create_id;
+ }
+
+ snprintf(port_str, 16, "%d", rdma->port);
+ port_str[15] = '\0';
+
+ ret = getaddrinfo(rdma->host, port_str, NULL, &res);
+ if (ret < 0) {
+ ERROR(errp, "could not getaddrinfo address %s\n", rdma->host);
+ goto err_resolve_get_addr;
+ }
+
+ inet_ntop(AF_INET, &((struct sockaddr_in *) res->ai_addr)->sin_addr,
+ ip, sizeof ip);
+ DPRINTF("%s => %s\n", rdma->host, ip);
+
+ /* resolve the first address */
+ ret = rdma_resolve_addr(rdma->cm_id, NULL, res->ai_addr,
+ RDMA_RESOLVE_TIMEOUT_MS);
+ if (ret) {
+ ERROR(errp, "could not resolve address %s\n", rdma->host);
+ goto err_resolve_get_addr;
+ }
+
+ qemu_rdma_dump_gid("source_resolve_addr", rdma->cm_id);
+
+ ret = rdma_get_cm_event(rdma->channel, &cm_event);
+ if (ret) {
+ ERROR(errp, "could not perform event_addr_resolved\n");
+ goto err_resolve_get_addr;
+ }
+
+ if (cm_event->event != RDMA_CM_EVENT_ADDR_RESOLVED) {
+ ERROR(errp, "result not equal to event_addr_resolved %s\n",
+ rdma_event_str(cm_event->event));
+ perror("rdma_resolve_addr");
+ goto err_resolve_get_addr;
+ }
+ rdma_ack_cm_event(cm_event);
+
+ /* resolve route */
+ ret = rdma_resolve_route(rdma->cm_id, RDMA_RESOLVE_TIMEOUT_MS);
+ if (ret) {
+ ERROR(errp, "could not resolve rdma route\n");
+ goto err_resolve_get_addr;
+ }
+
+ ret = rdma_get_cm_event(rdma->channel, &cm_event);
+ if (ret) {
+ ERROR(errp, "could not perform event_route_resolved\n");
+ goto err_resolve_get_addr;
+ }
+ if (cm_event->event != RDMA_CM_EVENT_ROUTE_RESOLVED) {
+ ERROR(errp, "result not equal to event_route_resolved: %s\n",
+ rdma_event_str(cm_event->event));
+ rdma_ack_cm_event(cm_event);
+ goto err_resolve_get_addr;
+ }
+ rdma_ack_cm_event(cm_event);
+ rdma->verbs = rdma->cm_id->verbs;
+ qemu_rdma_dump_id("source_resolve_host", rdma->cm_id->verbs);
+ qemu_rdma_dump_gid("source_resolve_host", rdma->cm_id);
+ return 0;
+
+err_resolve_get_addr:
+ rdma_destroy_id(rdma->cm_id);
+ rdma->cm_id = NULL;
+err_resolve_create_id:
+ rdma_destroy_event_channel(rdma->channel);
+ rdma->channel = NULL;
+
+ return -1;
+}
+
+/*
+ * Create protection domain and completion queues
+ */
+static int qemu_rdma_alloc_pd_cq(RDMAContext *rdma)
+{
+ /* allocate pd */
+ rdma->pd = ibv_alloc_pd(rdma->verbs);
+ if (!rdma->pd) {
+ fprintf(stderr, "failed to allocate protection domain\n");
+ return -1;
+ }
+
+ /* create completion channel */
+ rdma->comp_channel = ibv_create_comp_channel(rdma->verbs);
+ if (!rdma->comp_channel) {
+ fprintf(stderr, "failed to allocate completion channel\n");
+ goto err_alloc_pd_cq;
+ }
+
+ /*
+ * Completion queue can be filled by both read and write work requests,
+ * so must reflect the sum of both possible queue sizes.
+ */
+ rdma->cq = ibv_create_cq(rdma->verbs, (RDMA_SIGNALED_SEND_MAX * 3),
+ NULL, rdma->comp_channel, 0);
+ if (!rdma->cq) {
+ fprintf(stderr, "failed to allocate completion queue\n");
+ goto err_alloc_pd_cq;
+ }
+
+ return 0;
+
+err_alloc_pd_cq:
+ if (rdma->pd) {
+ ibv_dealloc_pd(rdma->pd);
+ }
+ if (rdma->comp_channel) {
+ ibv_destroy_comp_channel(rdma->comp_channel);
+ }
+ rdma->pd = NULL;
+ rdma->comp_channel = NULL;
+ return -1;
+
+}
+
+/*
+ * Create queue pairs.
+ */
+static int qemu_rdma_alloc_qp(RDMAContext *rdma)
+{
+ struct ibv_qp_init_attr attr = { 0 };
+ int ret;
+
+ attr.cap.max_send_wr = RDMA_SIGNALED_SEND_MAX;
+ attr.cap.max_recv_wr = 3;
+ attr.cap.max_send_sge = 1;
+ attr.cap.max_recv_sge = 1;
+ attr.send_cq = rdma->cq;
+ attr.recv_cq = rdma->cq;
+ attr.qp_type = IBV_QPT_RC;
+
+ ret = rdma_create_qp(rdma->cm_id, rdma->pd, &attr);
+ if (ret) {
+ return -1;
+ }
+
+ rdma->qp = rdma->cm_id->qp;
+ return 0;
+}
+
+static int qemu_rdma_reg_whole_ram_blocks(RDMAContext *rdma)
+{
+ int i;
+ RDMALocalBlocks *local = &rdma->local_ram_blocks;
+
+ for (i = 0; i < local->nb_blocks; i++) {
+ local->block[i].mr =
+ ibv_reg_mr(rdma->pd,
+ local->block[i].local_host_addr,
+ local->block[i].length,
+ IBV_ACCESS_LOCAL_WRITE |
+ IBV_ACCESS_REMOTE_WRITE
+ );
+ if (!local->block[i].mr) {
+ perror("Failed to register local dest ram block!\n");
+ break;
+ }
+ rdma->total_registrations++;
+ }
+
+ if (i >= local->nb_blocks) {
+ return 0;
+ }
+
+ for (i--; i >= 0; i--) {
+ ibv_dereg_mr(local->block[i].mr);
+ rdma->total_registrations--;
+ }
+
+ return -1;
+
+}
+
+/*
+ * Find the ram block that corresponds to the page requested to be
+ * transmitted by QEMU.
+ *
+ * Once the block is found, also identify which 'chunk' within that
+ * block that the page belongs to.
+ *
+ * This search cannot fail or the migration will fail.
+ */
+static int qemu_rdma_search_ram_block(RDMAContext *rdma,
+ uint64_t block_offset,
+ uint64_t offset,
+ uint64_t length,
+ uint64_t *block_index,
+ uint64_t *chunk_index)
+{
+ uint64_t current_addr = block_offset + offset;
+ RDMALocalBlock *block = g_hash_table_lookup(rdma->blockmap,
+ (void *) block_offset);
+ assert(block);
+ assert(current_addr >= block->offset);
+ assert((current_addr + length) <= (block->offset + block->length));
+
+ *block_index = block->index;
+ *chunk_index = ram_chunk_index(block->local_host_addr,
+ block->local_host_addr + (current_addr - block->offset));
+
+ return 0;
+}
+
+/*
+ * Register a chunk with IB. If the chunk was already registered
+ * previously, then skip.
+ *
+ * Also return the keys associated with the registration needed
+ * to perform the actual RDMA operation.
+ */
+static int qemu_rdma_register_and_get_keys(RDMAContext *rdma,
+ RDMALocalBlock *block, uint8_t *host_addr,
+ uint32_t *lkey, uint32_t *rkey, int chunk,
+ uint8_t *chunk_start, uint8_t *chunk_end)
+{
+ if (block->mr) {
+ if (lkey) {
+ *lkey = block->mr->lkey;
+ }
+ if (rkey) {
+ *rkey = block->mr->rkey;
+ }
+ return 0;
+ }
+
+ /* allocate memory to store chunk MRs */
+ if (!block->pmr) {
+ block->pmr = g_malloc0(block->nb_chunks * sizeof(struct ibv_mr *));
+ if (!block->pmr) {
+ return -1;
+ }
+ }
+
+ /*
+ * If 'rkey', then we're the destination, so grant access to the source.
+ *
+ * If 'lkey', then we're the source VM, so grant access only to ourselves.
+ */
+ if (!block->pmr[chunk]) {
+ uint64_t len = chunk_end - chunk_start;
+
+ DDPRINTF("Registering %" PRIu64 " bytes @ %p\n",
+ len, chunk_start);
+
+ block->pmr[chunk] = ibv_reg_mr(rdma->pd,
+ chunk_start, len,
+ (rkey ? (IBV_ACCESS_LOCAL_WRITE |
+ IBV_ACCESS_REMOTE_WRITE) : 0));
+
+ if (!block->pmr[chunk]) {
+ perror("Failed to register chunk!");
+ fprintf(stderr, "Chunk details: block: %d chunk index %d"
+ " start %" PRIu64 " end %" PRIu64 " host %" PRIu64
+ " local %" PRIu64 " registrations: %d\n",
+ block->index, chunk, (uint64_t) chunk_start,
+ (uint64_t) chunk_end, (uint64_t) host_addr,
+ (uint64_t) block->local_host_addr,
+ rdma->total_registrations);
+ return -1;
+ }
+ rdma->total_registrations++;
+ }
+
+ if (lkey) {
+ *lkey = block->pmr[chunk]->lkey;
+ }
+ if (rkey) {
+ *rkey = block->pmr[chunk]->rkey;
+ }
+ return 0;
+}
+
+/*
+ * Register (at connection time) the memory used for control
+ * channel messages.
+ */
+static int qemu_rdma_reg_control(RDMAContext *rdma, int idx)
+{
+ rdma->wr_data[idx].control_mr = ibv_reg_mr(rdma->pd,
+ rdma->wr_data[idx].control, RDMA_CONTROL_MAX_BUFFER,
+ IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);
+ if (rdma->wr_data[idx].control_mr) {
+ rdma->total_registrations++;
+ return 0;
+ }
+ fprintf(stderr, "qemu_rdma_reg_control failed!\n");
+ return -1;
+}
+
+const char *print_wrid(int wrid)
+{
+ if (wrid >= RDMA_WRID_RECV_CONTROL) {
+ return wrid_desc[RDMA_WRID_RECV_CONTROL];
+ }
+ return wrid_desc[wrid];
+}
+
+/*
+ * RDMA requires memory registration (mlock/pinning), but this is not good for
+ * overcommitment.
+ *
+ * In preparation for the future where LRU information or workload-specific
+ * writable writable working set memory access behavior is available to QEMU
+ * it would be nice to have in place the ability to UN-register/UN-pin
+ * particular memory regions from the RDMA hardware when it is determine that
+ * those regions of memory will likely not be accessed again in the near future.
+ *
+ * While we do not yet have such information right now, the following
+ * compile-time option allows us to perform a non-optimized version of this
+ * behavior.
+ *
+ * By uncommenting this option, you will cause *all* RDMA transfers to be
+ * unregistered immediately after the transfer completes on both sides of the
+ * connection. This has no effect in 'rdma-pin-all' mode, only regular mode.
+ *
+ * This will have a terrible impact on migration performance, so until future
+ * workload information or LRU information is available, do not attempt to use
+ * this feature except for basic testing.
+ */
+//#define RDMA_UNREGISTRATION_EXAMPLE
+
+/*
+ * Perform a non-optimized memory unregistration after every transfer
+ * for demonsration purposes, only if pin-all is not requested.
+ *
+ * Potential optimizations:
+ * 1. Start a new thread to run this function continuously
+ - for bit clearing
+ - and for receipt of unregister messages
+ * 2. Use an LRU.
+ * 3. Use workload hints.
+ */
+static int qemu_rdma_unregister_waiting(RDMAContext *rdma)
+{
+ while (rdma->unregistrations[rdma->unregister_current]) {
+ int ret;
+ uint64_t wr_id = rdma->unregistrations[rdma->unregister_current];
+ uint64_t chunk =
+ (wr_id & RDMA_WRID_CHUNK_MASK) >> RDMA_WRID_CHUNK_SHIFT;
+ uint64_t index =
+ (wr_id & RDMA_WRID_BLOCK_MASK) >> RDMA_WRID_BLOCK_SHIFT;
+ RDMALocalBlock *block =
+ &(rdma->local_ram_blocks.block[index]);
+ RDMARegister reg = { .current_index = index };
+ RDMAControlHeader resp = { .type = RDMA_CONTROL_UNREGISTER_FINISHED,
+ };
+ RDMAControlHeader head = { .len = sizeof(RDMARegister),
+ .type = RDMA_CONTROL_UNREGISTER_REQUEST,
+ .repeat = 1,
+ };
+
+ DDPRINTF("Processing unregister for chunk: %" PRIu64
+ " at position %d\n", chunk, rdma->unregister_current);
+
+ rdma->unregistrations[rdma->unregister_current] = 0;
+ rdma->unregister_current++;
+
+ if (rdma->unregister_current == RDMA_SIGNALED_SEND_MAX) {
+ rdma->unregister_current = 0;
+ }
+
+
+ /*
+ * Unregistration is speculative (because migration is single-threaded
+ * and we cannot break the protocol's inifinband message ordering).
+ * Thus, if the memory is currently being used for transmission,
+ * then abort the attempt to unregister and try again
+ * later the next time a completion is received for this memory.
+ */
+ clear_bit(chunk, block->unregister_bitmap);
+
+ if (test_bit(chunk, block->transit_bitmap)) {
+ DDPRINTF("Cannot unregister inflight chunk: %" PRIu64 "\n", chunk);
+ continue;
+ }
+
+ DDPRINTF("Sending unregister for chunk: %" PRIu64 "\n", chunk);
+
+ ret = ibv_dereg_mr(block->pmr[chunk]);
+ block->pmr[chunk] = NULL;
+ block->remote_keys[chunk] = 0;
+
+ if (ret != 0) {
+ perror("unregistration chunk failed");
+ return -ret;
+ }
+ rdma->total_registrations--;
+
+ reg.key.chunk = chunk;
+ register_to_network(&reg);
+ ret = qemu_rdma_exchange_send(rdma, &head, (uint8_t *) &reg,
+ &resp, NULL, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ DDPRINTF("Unregister for chunk: %" PRIu64 " complete.\n", chunk);
+ }
+
+ return 0;
+}
+
+static uint64_t qemu_rdma_make_wrid(uint64_t wr_id, uint64_t index,
+ uint64_t chunk)
+{
+ uint64_t result = wr_id & RDMA_WRID_TYPE_MASK;
+
+ result |= (index << RDMA_WRID_BLOCK_SHIFT);
+ result |= (chunk << RDMA_WRID_CHUNK_SHIFT);
+
+ return result;
+}
+
+/*
+ * Set bit for unregistration in the next iteration.
+ * We cannot transmit right here, but will unpin later.
+ */
+static void qemu_rdma_signal_unregister(RDMAContext *rdma, uint64_t index,
+ uint64_t chunk, uint64_t wr_id)
+{
+ if (rdma->unregistrations[rdma->unregister_next] != 0) {
+ fprintf(stderr, "rdma migration: queue is full!\n");
+ } else {
+ RDMALocalBlock *block = &(rdma->local_ram_blocks.block[index]);
+
+ if (!test_and_set_bit(chunk, block->unregister_bitmap)) {
+ DDPRINTF("Appending unregister chunk %" PRIu64
+ " at position %d\n", chunk, rdma->unregister_next);
+
+ rdma->unregistrations[rdma->unregister_next++] =
+ qemu_rdma_make_wrid(wr_id, index, chunk);
+
+ if (rdma->unregister_next == RDMA_SIGNALED_SEND_MAX) {
+ rdma->unregister_next = 0;
+ }
+ } else {
+ DDPRINTF("Unregister chunk %" PRIu64 " already in queue.\n",
+ chunk);
+ }
+ }
+}
+
+/*
+ * Consult the connection manager to see a work request
+ * (of any kind) has completed.
+ * Return the work request ID that completed.
+ */
+static uint64_t qemu_rdma_poll(RDMAContext *rdma, uint64_t *wr_id_out)
+{
+ int ret;
+ struct ibv_wc wc;
+ uint64_t wr_id;
+
+ ret = ibv_poll_cq(rdma->cq, 1, &wc);
+
+ if (!ret) {
+ *wr_id_out = RDMA_WRID_NONE;
+ return 0;
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "ibv_poll_cq return %d!\n", ret);
+ return ret;
+ }
+
+ wr_id = wc.wr_id & RDMA_WRID_TYPE_MASK;
+
+ if (wc.status != IBV_WC_SUCCESS) {
+ fprintf(stderr, "ibv_poll_cq wc.status=%d %s!\n",
+ wc.status, ibv_wc_status_str(wc.status));
+ fprintf(stderr, "ibv_poll_cq wrid=%s!\n", wrid_desc[wr_id]);
+
+ return -1;
+ }
+
+ if (rdma->control_ready_expected &&
+ (wr_id >= RDMA_WRID_RECV_CONTROL)) {
+ DDDPRINTF("completion %s #%" PRId64 " received (%" PRId64 ")"
+ " left %d\n", wrid_desc[RDMA_WRID_RECV_CONTROL],
+ wr_id - RDMA_WRID_RECV_CONTROL, wr_id, rdma->nb_sent);
+ rdma->control_ready_expected = 0;
+ }
+
+ if (wr_id == RDMA_WRID_RDMA_WRITE) {
+ uint64_t chunk =
+ (wc.wr_id & RDMA_WRID_CHUNK_MASK) >> RDMA_WRID_CHUNK_SHIFT;
+ uint64_t index =
+ (wc.wr_id & RDMA_WRID_BLOCK_MASK) >> RDMA_WRID_BLOCK_SHIFT;
+ RDMALocalBlock *block = &(rdma->local_ram_blocks.block[index]);
+
+ DDDPRINTF("completions %s (%" PRId64 ") left %d, "
+ "block %" PRIu64 ", chunk: %" PRIu64 " %p %p\n",
+ print_wrid(wr_id), wr_id, rdma->nb_sent, index, chunk,
+ block->local_host_addr, (void *)block->remote_host_addr);
+
+ clear_bit(chunk, block->transit_bitmap);
+
+ if (rdma->nb_sent > 0) {
+ rdma->nb_sent--;
+ }
+
+ if (!rdma->pin_all) {
+ /*
+ * FYI: If one wanted to signal a specific chunk to be unregistered
+ * using LRU or workload-specific information, this is the function
+ * you would call to do so. That chunk would then get asynchronously
+ * unregistered later.
+ */
+#ifdef RDMA_UNREGISTRATION_EXAMPLE
+ qemu_rdma_signal_unregister(rdma, index, chunk, wc.wr_id);
+#endif
+ }
+ } else {
+ DDDPRINTF("other completion %s (%" PRId64 ") received left %d\n",
+ print_wrid(wr_id), wr_id, rdma->nb_sent);
+ }
+
+ *wr_id_out = wc.wr_id;
+
+ return 0;
+}
+
+/*
+ * Block until the next work request has completed.
+ *
+ * First poll to see if a work request has already completed,
+ * otherwise block.
+ *
+ * If we encounter completed work requests for IDs other than
+ * the one we're interested in, then that's generally an error.
+ *
+ * The only exception is actual RDMA Write completions. These
+ * completions only need to be recorded, but do not actually
+ * need further processing.
+ */
+static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested)
+{
+ int num_cq_events = 0, ret = 0;
+ struct ibv_cq *cq;
+ void *cq_ctx;
+ uint64_t wr_id = RDMA_WRID_NONE, wr_id_in;
+
+ if (ibv_req_notify_cq(rdma->cq, 0)) {
+ return -1;
+ }
+ /* poll cq first */
+ while (wr_id != wrid_requested) {
+ ret = qemu_rdma_poll(rdma, &wr_id_in);
+ if (ret < 0) {
+ return ret;
+ }
+
+ wr_id = wr_id_in & RDMA_WRID_TYPE_MASK;
+
+ if (wr_id == RDMA_WRID_NONE) {
+ break;
+ }
+ if (wr_id != wrid_requested) {
+ DDDPRINTF("A Wanted wrid %s (%d) but got %s (%" PRIu64 ")\n",
+ print_wrid(wrid_requested),
+ wrid_requested, print_wrid(wr_id), wr_id);
+ }
+ }
+
+ if (wr_id == wrid_requested) {
+ return 0;
+ }
+
+ while (1) {
+ /*
+ * Coroutine doesn't start until process_incoming_migration()
+ * so don't yield unless we know we're running inside of a coroutine.
+ */
+ if (rdma->migration_started_on_destination) {
+ yield_until_fd_readable(rdma->comp_channel->fd);
+ }
+
+ if (ibv_get_cq_event(rdma->comp_channel, &cq, &cq_ctx)) {
+ perror("ibv_get_cq_event");
+ goto err_block_for_wrid;
+ }
+
+ num_cq_events++;
+
+ if (ibv_req_notify_cq(cq, 0)) {
+ goto err_block_for_wrid;
+ }
+
+ while (wr_id != wrid_requested) {
+ ret = qemu_rdma_poll(rdma, &wr_id_in);
+ if (ret < 0) {
+ goto err_block_for_wrid;
+ }
+
+ wr_id = wr_id_in & RDMA_WRID_TYPE_MASK;
+
+ if (wr_id == RDMA_WRID_NONE) {
+ break;
+ }
+ if (wr_id != wrid_requested) {
+ DDDPRINTF("B Wanted wrid %s (%d) but got %s (%" PRIu64 ")\n",
+ print_wrid(wrid_requested), wrid_requested,
+ print_wrid(wr_id), wr_id);
+ }
+ }
+
+ if (wr_id == wrid_requested) {
+ goto success_block_for_wrid;
+ }
+ }
+
+success_block_for_wrid:
+ if (num_cq_events) {
+ ibv_ack_cq_events(cq, num_cq_events);
+ }
+ return 0;
+
+err_block_for_wrid:
+ if (num_cq_events) {
+ ibv_ack_cq_events(cq, num_cq_events);
+ }
+ return ret;
+}
+
+/*
+ * Post a SEND message work request for the control channel
+ * containing some data and block until the post completes.
+ */
+static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf,
+ RDMAControlHeader *head)
+{
+ int ret = 0;
+ RDMAWorkRequestData *wr = &rdma->wr_data[RDMA_WRID_MAX];
+ struct ibv_send_wr *bad_wr;
+ struct ibv_sge sge = {
+ .addr = (uint64_t)(wr->control),
+ .length = head->len + sizeof(RDMAControlHeader),
+ .lkey = wr->control_mr->lkey,
+ };
+ struct ibv_send_wr send_wr = {
+ .wr_id = RDMA_WRID_SEND_CONTROL,
+ .opcode = IBV_WR_SEND,
+ .send_flags = IBV_SEND_SIGNALED,
+ .sg_list = &sge,
+ .num_sge = 1,
+ };
+
+ DDDPRINTF("CONTROL: sending %s..\n", control_desc[head->type]);
+
+ /*
+ * We don't actually need to do a memcpy() in here if we used
+ * the "sge" properly, but since we're only sending control messages
+ * (not RAM in a performance-critical path), then its OK for now.
+ *
+ * The copy makes the RDMAControlHeader simpler to manipulate
+ * for the time being.
+ */
+ memcpy(wr->control, head, sizeof(RDMAControlHeader));
+ control_to_network((void *) wr->control);
+
+ if (buf) {
+ memcpy(wr->control + sizeof(RDMAControlHeader), buf, head->len);
+ }
+
+
+ if (ibv_post_send(rdma->qp, &send_wr, &bad_wr)) {
+ return -1;
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to use post IB SEND for control!\n");
+ return ret;
+ }
+
+ ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_SEND_CONTROL);
+ if (ret < 0) {
+ fprintf(stderr, "rdma migration: send polling control error!\n");
+ }
+
+ return ret;
+}
+
+/*
+ * Post a RECV work request in anticipation of some future receipt
+ * of data on the control channel.
+ */
+static int qemu_rdma_post_recv_control(RDMAContext *rdma, int idx)
+{
+ struct ibv_recv_wr *bad_wr;
+ struct ibv_sge sge = {
+ .addr = (uint64_t)(rdma->wr_data[idx].control),
+ .length = RDMA_CONTROL_MAX_BUFFER,
+ .lkey = rdma->wr_data[idx].control_mr->lkey,
+ };
+
+ struct ibv_recv_wr recv_wr = {
+ .wr_id = RDMA_WRID_RECV_CONTROL + idx,
+ .sg_list = &sge,
+ .num_sge = 1,
+ };
+
+
+ if (ibv_post_recv(rdma->qp, &recv_wr, &bad_wr)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Block and wait for a RECV control channel message to arrive.
+ */
+static int qemu_rdma_exchange_get_response(RDMAContext *rdma,
+ RDMAControlHeader *head, int expecting, int idx)
+{
+ int ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RECV_CONTROL + idx);
+
+ if (ret < 0) {
+ fprintf(stderr, "rdma migration: recv polling control error!\n");
+ return ret;
+ }
+
+ network_to_control((void *) rdma->wr_data[idx].control);
+ memcpy(head, rdma->wr_data[idx].control, sizeof(RDMAControlHeader));
+
+ DDDPRINTF("CONTROL: %s receiving...\n", control_desc[expecting]);
+
+ if (expecting == RDMA_CONTROL_NONE) {
+ DDDPRINTF("Surprise: got %s (%d)\n",
+ control_desc[head->type], head->type);
+ } else if (head->type != expecting || head->type == RDMA_CONTROL_ERROR) {
+ fprintf(stderr, "Was expecting a %s (%d) control message"
+ ", but got: %s (%d), length: %d\n",
+ control_desc[expecting], expecting,
+ control_desc[head->type], head->type, head->len);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * When a RECV work request has completed, the work request's
+ * buffer is pointed at the header.
+ *
+ * This will advance the pointer to the data portion
+ * of the control message of the work request's buffer that
+ * was populated after the work request finished.
+ */
+static void qemu_rdma_move_header(RDMAContext *rdma, int idx,
+ RDMAControlHeader *head)
+{
+ rdma->wr_data[idx].control_len = head->len;
+ rdma->wr_data[idx].control_curr =
+ rdma->wr_data[idx].control + sizeof(RDMAControlHeader);
+}
+
+/*
+ * This is an 'atomic' high-level operation to deliver a single, unified
+ * control-channel message.
+ *
+ * Additionally, if the user is expecting some kind of reply to this message,
+ * they can request a 'resp' response message be filled in by posting an
+ * additional work request on behalf of the user and waiting for an additional
+ * completion.
+ *
+ * The extra (optional) response is used during registration to us from having
+ * to perform an *additional* exchange of message just to provide a response by
+ * instead piggy-backing on the acknowledgement.
+ */
+static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head,
+ uint8_t *data, RDMAControlHeader *resp,
+ int *resp_idx,
+ int (*callback)(RDMAContext *rdma))
+{
+ int ret = 0;
+
+ /*
+ * Wait until the dest is ready before attempting to deliver the message
+ * by waiting for a READY message.
+ */
+ if (rdma->control_ready_expected) {
+ RDMAControlHeader resp;
+ ret = qemu_rdma_exchange_get_response(rdma,
+ &resp, RDMA_CONTROL_READY, RDMA_WRID_READY);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ /*
+ * If the user is expecting a response, post a WR in anticipation of it.
+ */
+ if (resp) {
+ ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_DATA);
+ if (ret) {
+ fprintf(stderr, "rdma migration: error posting"
+ " extra control recv for anticipated result!");
+ return ret;
+ }
+ }
+
+ /*
+ * Post a WR to replace the one we just consumed for the READY message.
+ */
+ ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY);
+ if (ret) {
+ fprintf(stderr, "rdma migration: error posting first control recv!");
+ return ret;
+ }
+
+ /*
+ * Deliver the control message that was requested.
+ */
+ ret = qemu_rdma_post_send_control(rdma, data, head);
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to send control buffer!\n");
+ return ret;
+ }
+
+ /*
+ * If we're expecting a response, block and wait for it.
+ */
+ if (resp) {
+ if (callback) {
+ DDPRINTF("Issuing callback before receiving response...\n");
+ ret = callback(rdma);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ DDPRINTF("Waiting for response %s\n", control_desc[resp->type]);
+ ret = qemu_rdma_exchange_get_response(rdma, resp,
+ resp->type, RDMA_WRID_DATA);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ qemu_rdma_move_header(rdma, RDMA_WRID_DATA, resp);
+ if (resp_idx) {
+ *resp_idx = RDMA_WRID_DATA;
+ }
+ DDPRINTF("Response %s received.\n", control_desc[resp->type]);
+ }
+
+ rdma->control_ready_expected = 1;
+
+ return 0;
+}
+
+/*
+ * This is an 'atomic' high-level operation to receive a single, unified
+ * control-channel message.
+ */
+static int qemu_rdma_exchange_recv(RDMAContext *rdma, RDMAControlHeader *head,
+ int expecting)
+{
+ RDMAControlHeader ready = {
+ .len = 0,
+ .type = RDMA_CONTROL_READY,
+ .repeat = 1,
+ };
+ int ret;
+
+ /*
+ * Inform the source that we're ready to receive a message.
+ */
+ ret = qemu_rdma_post_send_control(rdma, NULL, &ready);
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to send control buffer!\n");
+ return ret;
+ }
+
+ /*
+ * Block and wait for the message.
+ */
+ ret = qemu_rdma_exchange_get_response(rdma, head,
+ expecting, RDMA_WRID_READY);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ qemu_rdma_move_header(rdma, RDMA_WRID_READY, head);
+
+ /*
+ * Post a new RECV work request to replace the one we just consumed.
+ */
+ ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY);
+ if (ret) {
+ fprintf(stderr, "rdma migration: error posting second control recv!");
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Write an actual chunk of memory using RDMA.
+ *
+ * If we're using dynamic registration on the dest-side, we have to
+ * send a registration command first.
+ */
+static int qemu_rdma_write_one(QEMUFile *f, RDMAContext *rdma,
+ int current_index, uint64_t current_addr,
+ uint64_t length)
+{
+ struct ibv_sge sge;
+ struct ibv_send_wr send_wr = { 0 };
+ struct ibv_send_wr *bad_wr;
+ int reg_result_idx, ret, count = 0;
+ uint64_t chunk, chunks;
+ uint8_t *chunk_start, *chunk_end;
+ RDMALocalBlock *block = &(rdma->local_ram_blocks.block[current_index]);
+ RDMARegister reg;
+ RDMARegisterResult *reg_result;
+ RDMAControlHeader resp = { .type = RDMA_CONTROL_REGISTER_RESULT };
+ RDMAControlHeader head = { .len = sizeof(RDMARegister),
+ .type = RDMA_CONTROL_REGISTER_REQUEST,
+ .repeat = 1,
+ };
+
+retry:
+ sge.addr = (uint64_t)(block->local_host_addr +
+ (current_addr - block->offset));
+ sge.length = length;
+
+ chunk = ram_chunk_index(block->local_host_addr, (uint8_t *) sge.addr);
+ chunk_start = ram_chunk_start(block, chunk);
+
+ if (block->is_ram_block) {
+ chunks = length / (1UL << RDMA_REG_CHUNK_SHIFT);
+
+ if (chunks && ((length % (1UL << RDMA_REG_CHUNK_SHIFT)) == 0)) {
+ chunks--;
+ }
+ } else {
+ chunks = block->length / (1UL << RDMA_REG_CHUNK_SHIFT);
+
+ if (chunks && ((block->length % (1UL << RDMA_REG_CHUNK_SHIFT)) == 0)) {
+ chunks--;
+ }
+ }
+
+ DDPRINTF("Writing %" PRIu64 " chunks, (%" PRIu64 " MB)\n",
+ chunks + 1, (chunks + 1) * (1UL << RDMA_REG_CHUNK_SHIFT) / 1024 / 1024);
+
+ chunk_end = ram_chunk_end(block, chunk + chunks);
+
+ if (!rdma->pin_all) {
+#ifdef RDMA_UNREGISTRATION_EXAMPLE
+ qemu_rdma_unregister_waiting(rdma);
+#endif
+ }
+
+ while (test_bit(chunk, block->transit_bitmap)) {
+ (void)count;
+ DDPRINTF("(%d) Not clobbering: block: %d chunk %" PRIu64
+ " current %" PRIu64 " len %" PRIu64 " %d %d\n",
+ count++, current_index, chunk,
+ sge.addr, length, rdma->nb_sent, block->nb_chunks);
+
+ ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE);
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to Wait for previous write to complete "
+ "block %d chunk %" PRIu64
+ " current %" PRIu64 " len %" PRIu64 " %d\n",
+ current_index, chunk, sge.addr, length, rdma->nb_sent);
+ return ret;
+ }
+ }
+
+ if (!rdma->pin_all || !block->is_ram_block) {
+ if (!block->remote_keys[chunk]) {
+ /*
+ * This chunk has not yet been registered, so first check to see
+ * if the entire chunk is zero. If so, tell the other size to
+ * memset() + madvise() the entire chunk without RDMA.
+ */
+
+ if (can_use_buffer_find_nonzero_offset((void *)sge.addr, length)
+ && buffer_find_nonzero_offset((void *)sge.addr,
+ length) == length) {
+ RDMACompress comp = {
+ .offset = current_addr,
+ .value = 0,
+ .block_idx = current_index,
+ .length = length,
+ };
+
+ head.len = sizeof(comp);
+ head.type = RDMA_CONTROL_COMPRESS;
+
+ DDPRINTF("Entire chunk is zero, sending compress: %"
+ PRIu64 " for %d "
+ "bytes, index: %d, offset: %" PRId64 "...\n",
+ chunk, sge.length, current_index, current_addr);
+
+ compress_to_network(&comp);
+ ret = qemu_rdma_exchange_send(rdma, &head,
+ (uint8_t *) &comp, NULL, NULL, NULL);
+
+ if (ret < 0) {
+ return -EIO;
+ }
+
+ acct_update_position(f, sge.length, true);
+
+ return 1;
+ }
+
+ /*
+ * Otherwise, tell other side to register.
+ */
+ reg.current_index = current_index;
+ if (block->is_ram_block) {
+ reg.key.current_addr = current_addr;
+ } else {
+ reg.key.chunk = chunk;
+ }
+ reg.chunks = chunks;
+
+ DDPRINTF("Sending registration request chunk %" PRIu64 " for %d "
+ "bytes, index: %d, offset: %" PRId64 "...\n",
+ chunk, sge.length, current_index, current_addr);
+
+ register_to_network(&reg);
+ ret = qemu_rdma_exchange_send(rdma, &head, (uint8_t *) &reg,
+ &resp, &reg_result_idx, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* try to overlap this single registration with the one we sent. */
+ if (qemu_rdma_register_and_get_keys(rdma, block,
+ (uint8_t *) sge.addr,
+ &sge.lkey, NULL, chunk,
+ chunk_start, chunk_end)) {
+ fprintf(stderr, "cannot get lkey!\n");
+ return -EINVAL;
+ }
+
+ reg_result = (RDMARegisterResult *)
+ rdma->wr_data[reg_result_idx].control_curr;
+
+ network_to_result(reg_result);
+
+ DDPRINTF("Received registration result:"
+ " my key: %x their key %x, chunk %" PRIu64 "\n",
+ block->remote_keys[chunk], reg_result->rkey, chunk);
+
+ block->remote_keys[chunk] = reg_result->rkey;
+ block->remote_host_addr = reg_result->host_addr;
+ } else {
+ /* already registered before */
+ if (qemu_rdma_register_and_get_keys(rdma, block,
+ (uint8_t *)sge.addr,
+ &sge.lkey, NULL, chunk,
+ chunk_start, chunk_end)) {
+ fprintf(stderr, "cannot get lkey!\n");
+ return -EINVAL;
+ }
+ }
+
+ send_wr.wr.rdma.rkey = block->remote_keys[chunk];
+ } else {
+ send_wr.wr.rdma.rkey = block->remote_rkey;
+
+ if (qemu_rdma_register_and_get_keys(rdma, block, (uint8_t *)sge.addr,
+ &sge.lkey, NULL, chunk,
+ chunk_start, chunk_end)) {
+ fprintf(stderr, "cannot get lkey!\n");
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Encode the ram block index and chunk within this wrid.
+ * We will use this information at the time of completion
+ * to figure out which bitmap to check against and then which
+ * chunk in the bitmap to look for.
+ */
+ send_wr.wr_id = qemu_rdma_make_wrid(RDMA_WRID_RDMA_WRITE,
+ current_index, chunk);
+
+ send_wr.opcode = IBV_WR_RDMA_WRITE;
+ send_wr.send_flags = IBV_SEND_SIGNALED;
+ send_wr.sg_list = &sge;
+ send_wr.num_sge = 1;
+ send_wr.wr.rdma.remote_addr = block->remote_host_addr +
+ (current_addr - block->offset);
+
+ DDDPRINTF("Posting chunk: %" PRIu64 ", addr: %lx"
+ " remote: %lx, bytes %" PRIu32 "\n",
+ chunk, sge.addr, send_wr.wr.rdma.remote_addr,
+ sge.length);
+
+ /*
+ * ibv_post_send() does not return negative error numbers,
+ * per the specification they are positive - no idea why.
+ */
+ ret = ibv_post_send(rdma->qp, &send_wr, &bad_wr);
+
+ if (ret == ENOMEM) {
+ DDPRINTF("send queue is full. wait a little....\n");
+ ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE);
+ if (ret < 0) {
+ fprintf(stderr, "rdma migration: failed to make "
+ "room in full send queue! %d\n", ret);
+ return ret;
+ }
+
+ goto retry;
+
+ } else if (ret > 0) {
+ perror("rdma migration: post rdma write failed");
+ return -ret;
+ }
+
+ set_bit(chunk, block->transit_bitmap);
+ acct_update_position(f, sge.length, false);
+ rdma->total_writes++;
+
+ return 0;
+}
+
+/*
+ * Push out any unwritten RDMA operations.
+ *
+ * We support sending out multiple chunks at the same time.
+ * Not all of them need to get signaled in the completion queue.
+ */
+static int qemu_rdma_write_flush(QEMUFile *f, RDMAContext *rdma)
+{
+ int ret;
+
+ if (!rdma->current_length) {
+ return 0;
+ }
+
+ ret = qemu_rdma_write_one(f, rdma,
+ rdma->current_index, rdma->current_addr, rdma->current_length);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (ret == 0) {
+ rdma->nb_sent++;
+ DDDPRINTF("sent total: %d\n", rdma->nb_sent);
+ }
+
+ rdma->current_length = 0;
+ rdma->current_addr = 0;
+
+ return 0;
+}
+
+static inline int qemu_rdma_buffer_mergable(RDMAContext *rdma,
+ uint64_t offset, uint64_t len)
+{
+ RDMALocalBlock *block =
+ &(rdma->local_ram_blocks.block[rdma->current_index]);
+ uint8_t *host_addr = block->local_host_addr + (offset - block->offset);
+ uint8_t *chunk_end = ram_chunk_end(block, rdma->current_chunk);
+
+ if (rdma->current_length == 0) {
+ return 0;
+ }
+
+ /*
+ * Only merge into chunk sequentially.
+ */
+ if (offset != (rdma->current_addr + rdma->current_length)) {
+ return 0;
+ }
+
+ if (rdma->current_index < 0) {
+ return 0;
+ }
+
+ if (offset < block->offset) {
+ return 0;
+ }
+
+ if ((offset + len) > (block->offset + block->length)) {
+ return 0;
+ }
+
+ if (rdma->current_chunk < 0) {
+ return 0;
+ }
+
+ if ((host_addr + len) > chunk_end) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * We're not actually writing here, but doing three things:
+ *
+ * 1. Identify the chunk the buffer belongs to.
+ * 2. If the chunk is full or the buffer doesn't belong to the current
+ * chunk, then start a new chunk and flush() the old chunk.
+ * 3. To keep the hardware busy, we also group chunks into batches
+ * and only require that a batch gets acknowledged in the completion
+ * qeueue instead of each individual chunk.
+ */
+static int qemu_rdma_write(QEMUFile *f, RDMAContext *rdma,
+ uint64_t block_offset, uint64_t offset,
+ uint64_t len)
+{
+ uint64_t current_addr = block_offset + offset;
+ uint64_t index = rdma->current_index;
+ uint64_t chunk = rdma->current_chunk;
+ int ret;
+
+ /* If we cannot merge it, we flush the current buffer first. */
+ if (!qemu_rdma_buffer_mergable(rdma, current_addr, len)) {
+ ret = qemu_rdma_write_flush(f, rdma);
+ if (ret) {
+ return ret;
+ }
+ rdma->current_length = 0;
+ rdma->current_addr = current_addr;
+
+ ret = qemu_rdma_search_ram_block(rdma, block_offset,
+ offset, len, &index, &chunk);
+ if (ret) {
+ fprintf(stderr, "ram block search failed\n");
+ return ret;
+ }
+ rdma->current_index = index;
+ rdma->current_chunk = chunk;
+ }
+
+ /* merge it */
+ rdma->current_length += len;
+
+ /* flush it if buffer is too large */
+ if (rdma->current_length >= RDMA_MERGE_MAX) {
+ return qemu_rdma_write_flush(f, rdma);
+ }
+
+ return 0;
+}
+
+static void qemu_rdma_cleanup(RDMAContext *rdma)
+{
+ struct rdma_cm_event *cm_event;
+ int ret, idx;
+
+ if (rdma->cm_id) {
+ if (rdma->error_state) {
+ RDMAControlHeader head = { .len = 0,
+ .type = RDMA_CONTROL_ERROR,
+ .repeat = 1,
+ };
+ fprintf(stderr, "Early error. Sending error.\n");
+ qemu_rdma_post_send_control(rdma, NULL, &head);
+ }
+
+ ret = rdma_disconnect(rdma->cm_id);
+ if (!ret) {
+ DDPRINTF("waiting for disconnect\n");
+ ret = rdma_get_cm_event(rdma->channel, &cm_event);
+ if (!ret) {
+ rdma_ack_cm_event(cm_event);
+ }
+ }
+ DDPRINTF("Disconnected.\n");
+ rdma->cm_id = NULL;
+ }
+
+ g_free(rdma->block);
+ rdma->block = NULL;
+
+ for (idx = 0; idx <= RDMA_WRID_MAX; idx++) {
+ if (rdma->wr_data[idx].control_mr) {
+ rdma->total_registrations--;
+ ibv_dereg_mr(rdma->wr_data[idx].control_mr);
+ }
+ rdma->wr_data[idx].control_mr = NULL;
+ }
+
+ if (rdma->local_ram_blocks.block) {
+ while (rdma->local_ram_blocks.nb_blocks) {
+ __qemu_rdma_delete_block(rdma,
+ rdma->local_ram_blocks.block->offset);
+ }
+ }
+
+ if (rdma->qp) {
+ ibv_destroy_qp(rdma->qp);
+ rdma->qp = NULL;
+ }
+ if (rdma->cq) {
+ ibv_destroy_cq(rdma->cq);
+ rdma->cq = NULL;
+ }
+ if (rdma->comp_channel) {
+ ibv_destroy_comp_channel(rdma->comp_channel);
+ rdma->comp_channel = NULL;
+ }
+ if (rdma->pd) {
+ ibv_dealloc_pd(rdma->pd);
+ rdma->pd = NULL;
+ }
+ if (rdma->listen_id) {
+ rdma_destroy_id(rdma->listen_id);
+ rdma->listen_id = NULL;
+ }
+ if (rdma->cm_id) {
+ rdma_destroy_id(rdma->cm_id);
+ rdma->cm_id = NULL;
+ }
+ if (rdma->channel) {
+ rdma_destroy_event_channel(rdma->channel);
+ rdma->channel = NULL;
+ }
+}
+
+
+static int qemu_rdma_source_init(RDMAContext *rdma, Error **errp, bool pin_all)
+{
+ int ret, idx;
+ Error *local_err = NULL, **temp = &local_err;
+
+ /*
+ * Will be validated against destination's actual capabilities
+ * after the connect() completes.
+ */
+ rdma->pin_all = pin_all;
+
+ ret = qemu_rdma_resolve_host(rdma, temp);
+ if (ret) {
+ goto err_rdma_source_init;
+ }
+
+ ret = qemu_rdma_alloc_pd_cq(rdma);
+ if (ret) {
+ ERROR(temp, "rdma migration: error allocating pd and cq! Your mlock()"
+ " limits may be too low. Please check $ ulimit -a # and "
+ "search for 'ulimit -l' in the output\n");
+ goto err_rdma_source_init;
+ }
+
+ ret = qemu_rdma_alloc_qp(rdma);
+ if (ret) {
+ ERROR(temp, "rdma migration: error allocating qp!\n");
+ goto err_rdma_source_init;
+ }
+
+ ret = qemu_rdma_init_ram_blocks(rdma);
+ if (ret) {
+ ERROR(temp, "rdma migration: error initializing ram blocks!\n");
+ goto err_rdma_source_init;
+ }
+
+ for (idx = 0; idx <= RDMA_WRID_MAX; idx++) {
+ ret = qemu_rdma_reg_control(rdma, idx);
+ if (ret) {
+ ERROR(temp, "rdma migration: error registering %d control!\n",
+ idx);
+ goto err_rdma_source_init;
+ }
+ }
+
+ return 0;
+
+err_rdma_source_init:
+ error_propagate(errp, local_err);
+ qemu_rdma_cleanup(rdma);
+ return -1;
+}
+
+static int qemu_rdma_connect(RDMAContext *rdma, Error **errp)
+{
+ RDMACapabilities cap = {
+ .version = RDMA_CONTROL_VERSION_CURRENT,
+ .flags = 0,
+ };
+ struct rdma_conn_param conn_param = { .initiator_depth = 2,
+ .retry_count = 5,
+ .private_data = &cap,
+ .private_data_len = sizeof(cap),
+ };
+ struct rdma_cm_event *cm_event;
+ int ret;
+
+ /*
+ * Only negotiate the capability with destination if the user
+ * on the source first requested the capability.
+ */
+ if (rdma->pin_all) {
+ DPRINTF("Server pin-all memory requested.\n");
+ cap.flags |= RDMA_CAPABILITY_PIN_ALL;
+ }
+
+ caps_to_network(&cap);
+
+ ret = rdma_connect(rdma->cm_id, &conn_param);
+ if (ret) {
+ perror("rdma_connect");
+ ERROR(errp, "connecting to destination!\n");
+ rdma_destroy_id(rdma->cm_id);
+ rdma->cm_id = NULL;
+ goto err_rdma_source_connect;
+ }
+
+ ret = rdma_get_cm_event(rdma->channel, &cm_event);
+ if (ret) {
+ perror("rdma_get_cm_event after rdma_connect");
+ ERROR(errp, "connecting to destination!\n");
+ rdma_ack_cm_event(cm_event);
+ rdma_destroy_id(rdma->cm_id);
+ rdma->cm_id = NULL;
+ goto err_rdma_source_connect;
+ }
+
+ if (cm_event->event != RDMA_CM_EVENT_ESTABLISHED) {
+ perror("rdma_get_cm_event != EVENT_ESTABLISHED after rdma_connect");
+ ERROR(errp, "connecting to destination!\n");
+ rdma_ack_cm_event(cm_event);
+ rdma_destroy_id(rdma->cm_id);
+ rdma->cm_id = NULL;
+ goto err_rdma_source_connect;
+ }
+
+ memcpy(&cap, cm_event->param.conn.private_data, sizeof(cap));
+ network_to_caps(&cap);
+
+ /*
+ * Verify that the *requested* capabilities are supported by the destination
+ * and disable them otherwise.
+ */
+ if (rdma->pin_all && !(cap.flags & RDMA_CAPABILITY_PIN_ALL)) {
+ ERROR(errp, "Server cannot support pinning all memory. "
+ "Will register memory dynamically.\n");
+ rdma->pin_all = false;
+ }
+
+ DPRINTF("Pin all memory: %s\n", rdma->pin_all ? "enabled" : "disabled");
+
+ rdma_ack_cm_event(cm_event);
+
+ ret = qemu_rdma_post_recv_control(rdma, 0);
+ if (ret) {
+ ERROR(errp, "posting second control recv!\n");
+ goto err_rdma_source_connect;
+ }
+
+ rdma->control_ready_expected = 1;
+ rdma->nb_sent = 0;
+ return 0;
+
+err_rdma_source_connect:
+ qemu_rdma_cleanup(rdma);
+ return -1;
+}
+
+static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp)
+{
+ int ret = -EINVAL, idx;
+ struct sockaddr_in sin;
+ struct rdma_cm_id *listen_id;
+ char ip[40] = "unknown";
+
+ for (idx = 0; idx <= RDMA_WRID_MAX; idx++) {
+ rdma->wr_data[idx].control_len = 0;
+ rdma->wr_data[idx].control_curr = NULL;
+ }
+
+ if (rdma->host == NULL) {
+ ERROR(errp, "RDMA host is not set!\n");
+ rdma->error_state = -EINVAL;
+ return -1;
+ }
+ /* create CM channel */
+ rdma->channel = rdma_create_event_channel();
+ if (!rdma->channel) {
+ ERROR(errp, "could not create rdma event channel\n");
+ rdma->error_state = -EINVAL;
+ return -1;
+ }
+
+ /* create CM id */
+ ret = rdma_create_id(rdma->channel, &listen_id, NULL, RDMA_PS_TCP);
+ if (ret) {
+ ERROR(errp, "could not create cm_id!\n");
+ goto err_dest_init_create_listen_id;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(rdma->port);
+
+ if (rdma->host && strcmp("", rdma->host)) {
+ struct hostent *dest_addr;
+ dest_addr = gethostbyname(rdma->host);
+ if (!dest_addr) {
+ ERROR(errp, "migration could not gethostbyname!\n");
+ ret = -EINVAL;
+ goto err_dest_init_bind_addr;
+ }
+ memcpy(&sin.sin_addr.s_addr, dest_addr->h_addr,
+ dest_addr->h_length);
+ inet_ntop(AF_INET, dest_addr->h_addr, ip, sizeof ip);
+ } else {
+ sin.sin_addr.s_addr = INADDR_ANY;
+ }
+
+ DPRINTF("%s => %s\n", rdma->host, ip);
+
+ ret = rdma_bind_addr(listen_id, (struct sockaddr *)&sin);
+ if (ret) {
+ ERROR(errp, "Error: could not rdma_bind_addr!\n");
+ goto err_dest_init_bind_addr;
+ }
+
+ rdma->listen_id = listen_id;
+ qemu_rdma_dump_gid("dest_init", listen_id);
+ return 0;
+
+err_dest_init_bind_addr:
+ rdma_destroy_id(listen_id);
+err_dest_init_create_listen_id:
+ rdma_destroy_event_channel(rdma->channel);
+ rdma->channel = NULL;
+ rdma->error_state = ret;
+ return ret;
+
+}
+
+static void *qemu_rdma_data_init(const char *host_port, Error **errp)
+{
+ RDMAContext *rdma = NULL;
+ InetSocketAddress *addr;
+
+ if (host_port) {
+ rdma = g_malloc0(sizeof(RDMAContext));
+ memset(rdma, 0, sizeof(RDMAContext));
+ rdma->current_index = -1;
+ rdma->current_chunk = -1;
+
+ addr = inet_parse(host_port, NULL);
+ if (addr != NULL) {
+ rdma->port = atoi(addr->port);
+ rdma->host = g_strdup(addr->host);
+ } else {
+ ERROR(errp, "bad RDMA migration address '%s'", host_port);
+ g_free(rdma);
+ return NULL;
+ }
+ }
+
+ return rdma;
+}
+
+/*
+ * QEMUFile interface to the control channel.
+ * SEND messages for control only.
+ * pc.ram is handled with regular RDMA messages.
+ */
+static int qemu_rdma_put_buffer(void *opaque, const uint8_t *buf,
+ int64_t pos, int size)
+{
+ QEMUFileRDMA *r = opaque;
+ QEMUFile *f = r->file;
+ RDMAContext *rdma = r->rdma;
+ size_t remaining = size;
+ uint8_t * data = (void *) buf;
+ int ret;
+
+ CHECK_ERROR_STATE();
+
+ /*
+ * Push out any writes that
+ * we're queued up for pc.ram.
+ */
+ ret = qemu_rdma_write_flush(f, rdma);
+ if (ret < 0) {
+ rdma->error_state = ret;
+ return ret;
+ }
+
+ while (remaining) {
+ RDMAControlHeader head;
+
+ r->len = MIN(remaining, RDMA_SEND_INCREMENT);
+ remaining -= r->len;
+
+ head.len = r->len;
+ head.type = RDMA_CONTROL_QEMU_FILE;
+
+ ret = qemu_rdma_exchange_send(rdma, &head, data, NULL, NULL, NULL);
+
+ if (ret < 0) {
+ rdma->error_state = ret;
+ return ret;
+ }
+
+ data += r->len;
+ }
+
+ return size;
+}
+
+static size_t qemu_rdma_fill(RDMAContext *rdma, uint8_t *buf,
+ int size, int idx)
+{
+ size_t len = 0;
+
+ if (rdma->wr_data[idx].control_len) {
+ DDDPRINTF("RDMA %" PRId64 " of %d bytes already in buffer\n",
+ rdma->wr_data[idx].control_len, size);
+
+ len = MIN(size, rdma->wr_data[idx].control_len);
+ memcpy(buf, rdma->wr_data[idx].control_curr, len);
+ rdma->wr_data[idx].control_curr += len;
+ rdma->wr_data[idx].control_len -= len;
+ }
+
+ return len;
+}
+
+/*
+ * QEMUFile interface to the control channel.
+ * RDMA links don't use bytestreams, so we have to
+ * return bytes to QEMUFile opportunistically.
+ */
+static int qemu_rdma_get_buffer(void *opaque, uint8_t *buf,
+ int64_t pos, int size)
+{
+ QEMUFileRDMA *r = opaque;
+ RDMAContext *rdma = r->rdma;
+ RDMAControlHeader head;
+ int ret = 0;
+
+ CHECK_ERROR_STATE();
+
+ /*
+ * First, we hold on to the last SEND message we
+ * were given and dish out the bytes until we run
+ * out of bytes.
+ */
+ r->len = qemu_rdma_fill(r->rdma, buf, size, 0);
+ if (r->len) {
+ return r->len;
+ }
+
+ /*
+ * Once we run out, we block and wait for another
+ * SEND message to arrive.
+ */
+ ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
+
+ if (ret < 0) {
+ rdma->error_state = ret;
+ return ret;
+ }
+
+ /*
+ * SEND was received with new bytes, now try again.
+ */
+ return qemu_rdma_fill(r->rdma, buf, size, 0);
+}
+
+/*
+ * Block until all the outstanding chunks have been delivered by the hardware.
+ */
+static int qemu_rdma_drain_cq(QEMUFile *f, RDMAContext *rdma)
+{
+ int ret;
+
+ if (qemu_rdma_write_flush(f, rdma) < 0) {
+ return -EIO;
+ }
+
+ while (rdma->nb_sent) {
+ ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE);
+ if (ret < 0) {
+ fprintf(stderr, "rdma migration: complete polling error!\n");
+ return -EIO;
+ }
+ }
+
+ qemu_rdma_unregister_waiting(rdma);
+
+ return 0;
+}
+
+static int qemu_rdma_close(void *opaque)
+{
+ DPRINTF("Shutting down connection.\n");
+ QEMUFileRDMA *r = opaque;
+ if (r->rdma) {
+ qemu_rdma_cleanup(r->rdma);
+ g_free(r->rdma);
+ }
+ g_free(r);
+ return 0;
+}
+
+/*
+ * Parameters:
+ * @offset == 0 :
+ * This means that 'block_offset' is a full virtual address that does not
+ * belong to a RAMBlock of the virtual machine and instead
+ * represents a private malloc'd memory area that the caller wishes to
+ * transfer.
+ *
+ * @offset != 0 :
+ * Offset is an offset to be added to block_offset and used
+ * to also lookup the corresponding RAMBlock.
+ *
+ * @size > 0 :
+ * Initiate an transfer this size.
+ *
+ * @size == 0 :
+ * A 'hint' or 'advice' that means that we wish to speculatively
+ * and asynchronously unregister this memory. In this case, there is no
+ * gaurantee that the unregister will actually happen, for example,
+ * if the memory is being actively transmitted. Additionally, the memory
+ * may be re-registered at any future time if a write within the same
+ * chunk was requested again, even if you attempted to unregister it
+ * here.
+ *
+ * @size < 0 : TODO, not yet supported
+ * Unregister the memory NOW. This means that the caller does not
+ * expect there to be any future RDMA transfers and we just want to clean
+ * things up. This is used in case the upper layer owns the memory and
+ * cannot wait for qemu_fclose() to occur.
+ *
+ * @bytes_sent : User-specificed pointer to indicate how many bytes were
+ * sent. Usually, this will not be more than a few bytes of
+ * the protocol because most transfers are sent asynchronously.
+ */
+static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque,
+ ram_addr_t block_offset, ram_addr_t offset,
+ size_t size, int *bytes_sent)
+{
+ QEMUFileRDMA *rfile = opaque;
+ RDMAContext *rdma = rfile->rdma;
+ int ret;
+
+ CHECK_ERROR_STATE();
+
+ qemu_fflush(f);
+
+ if (size > 0) {
+ /*
+ * Add this page to the current 'chunk'. If the chunk
+ * is full, or the page doen't belong to the current chunk,
+ * an actual RDMA write will occur and a new chunk will be formed.
+ */
+ ret = qemu_rdma_write(f, rdma, block_offset, offset, size);
+ if (ret < 0) {
+ fprintf(stderr, "rdma migration: write error! %d\n", ret);
+ goto err;
+ }
+
+ /*
+ * We always return 1 bytes because the RDMA
+ * protocol is completely asynchronous. We do not yet know
+ * whether an identified chunk is zero or not because we're
+ * waiting for other pages to potentially be merged with
+ * the current chunk. So, we have to call qemu_update_position()
+ * later on when the actual write occurs.
+ */
+ if (bytes_sent) {
+ *bytes_sent = 1;
+ }
+ } else {
+ uint64_t index, chunk;
+
+ /* TODO: Change QEMUFileOps prototype to be signed: size_t => long
+ if (size < 0) {
+ ret = qemu_rdma_drain_cq(f, rdma);
+ if (ret < 0) {
+ fprintf(stderr, "rdma: failed to synchronously drain"
+ " completion queue before unregistration.\n");
+ goto err;
+ }
+ }
+ */
+
+ ret = qemu_rdma_search_ram_block(rdma, block_offset,
+ offset, size, &index, &chunk);
+
+ if (ret) {
+ fprintf(stderr, "ram block search failed\n");
+ goto err;
+ }
+
+ qemu_rdma_signal_unregister(rdma, index, chunk, 0);
+
+ /*
+ * TODO: Synchronous, gauranteed unregistration (should not occur during
+ * fast-path). Otherwise, unregisters will process on the next call to
+ * qemu_rdma_drain_cq()
+ if (size < 0) {
+ qemu_rdma_unregister_waiting(rdma);
+ }
+ */
+ }
+
+ /*
+ * Drain the Completion Queue if possible, but do not block,
+ * just poll.
+ *
+ * If nothing to poll, the end of the iteration will do this
+ * again to make sure we don't overflow the request queue.
+ */
+ while (1) {
+ uint64_t wr_id, wr_id_in;
+ int ret = qemu_rdma_poll(rdma, &wr_id_in);
+ if (ret < 0) {
+ fprintf(stderr, "rdma migration: polling error! %d\n", ret);
+ goto err;
+ }
+
+ wr_id = wr_id_in & RDMA_WRID_TYPE_MASK;
+
+ if (wr_id == RDMA_WRID_NONE) {
+ break;
+ }
+ }
+
+ return RAM_SAVE_CONTROL_DELAYED;
+err:
+ rdma->error_state = ret;
+ return ret;
+}
+
+static int qemu_rdma_accept(RDMAContext *rdma)
+{
+ RDMACapabilities cap;
+ struct rdma_conn_param conn_param = {
+ .responder_resources = 2,
+ .private_data = &cap,
+ .private_data_len = sizeof(cap),
+ };
+ struct rdma_cm_event *cm_event;
+ struct ibv_context *verbs;
+ int ret = -EINVAL;
+ int idx;
+
+ ret = rdma_get_cm_event(rdma->channel, &cm_event);
+ if (ret) {
+ goto err_rdma_dest_wait;
+ }
+
+ if (cm_event->event != RDMA_CM_EVENT_CONNECT_REQUEST) {
+ rdma_ack_cm_event(cm_event);
+ goto err_rdma_dest_wait;
+ }
+
+ memcpy(&cap, cm_event->param.conn.private_data, sizeof(cap));
+
+ network_to_caps(&cap);
+
+ if (cap.version < 1 || cap.version > RDMA_CONTROL_VERSION_CURRENT) {
+ fprintf(stderr, "Unknown source RDMA version: %d, bailing...\n",
+ cap.version);
+ rdma_ack_cm_event(cm_event);
+ goto err_rdma_dest_wait;
+ }
+
+ /*
+ * Respond with only the capabilities this version of QEMU knows about.
+ */
+ cap.flags &= known_capabilities;
+
+ /*
+ * Enable the ones that we do know about.
+ * Add other checks here as new ones are introduced.
+ */
+ if (cap.flags & RDMA_CAPABILITY_PIN_ALL) {
+ rdma->pin_all = true;
+ }
+
+ rdma->cm_id = cm_event->id;
+ verbs = cm_event->id->verbs;
+
+ rdma_ack_cm_event(cm_event);
+
+ DPRINTF("Memory pin all: %s\n", rdma->pin_all ? "enabled" : "disabled");
+
+ caps_to_network(&cap);
+
+ DPRINTF("verbs context after listen: %p\n", verbs);
+
+ if (!rdma->verbs) {
+ rdma->verbs = verbs;
+ } else if (rdma->verbs != verbs) {
+ fprintf(stderr, "ibv context not matching %p, %p!\n",
+ rdma->verbs, verbs);
+ goto err_rdma_dest_wait;
+ }
+
+ qemu_rdma_dump_id("dest_init", verbs);
+
+ ret = qemu_rdma_alloc_pd_cq(rdma);
+ if (ret) {
+ fprintf(stderr, "rdma migration: error allocating pd and cq!\n");
+ goto err_rdma_dest_wait;
+ }
+
+ ret = qemu_rdma_alloc_qp(rdma);
+ if (ret) {
+ fprintf(stderr, "rdma migration: error allocating qp!\n");
+ goto err_rdma_dest_wait;
+ }
+
+ ret = qemu_rdma_init_ram_blocks(rdma);
+ if (ret) {
+ fprintf(stderr, "rdma migration: error initializing ram blocks!\n");
+ goto err_rdma_dest_wait;
+ }
+
+ for (idx = 0; idx <= RDMA_WRID_MAX; idx++) {
+ ret = qemu_rdma_reg_control(rdma, idx);
+ if (ret) {
+ fprintf(stderr, "rdma: error registering %d control!\n", idx);
+ goto err_rdma_dest_wait;
+ }
+ }
+
+ qemu_set_fd_handler2(rdma->channel->fd, NULL, NULL, NULL, NULL);
+
+ ret = rdma_accept(rdma->cm_id, &conn_param);
+ if (ret) {
+ fprintf(stderr, "rdma_accept returns %d!\n", ret);
+ goto err_rdma_dest_wait;
+ }
+
+ ret = rdma_get_cm_event(rdma->channel, &cm_event);
+ if (ret) {
+ fprintf(stderr, "rdma_accept get_cm_event failed %d!\n", ret);
+ goto err_rdma_dest_wait;
+ }
+
+ if (cm_event->event != RDMA_CM_EVENT_ESTABLISHED) {
+ fprintf(stderr, "rdma_accept not event established!\n");
+ rdma_ack_cm_event(cm_event);
+ goto err_rdma_dest_wait;
+ }
+
+ rdma_ack_cm_event(cm_event);
+
+ ret = qemu_rdma_post_recv_control(rdma, 0);
+ if (ret) {
+ fprintf(stderr, "rdma migration: error posting second control recv!\n");
+ goto err_rdma_dest_wait;
+ }
+
+ qemu_rdma_dump_gid("dest_connect", rdma->cm_id);
+
+ return 0;
+
+err_rdma_dest_wait:
+ rdma->error_state = ret;
+ qemu_rdma_cleanup(rdma);
+ return ret;
+}
+
+/*
+ * During each iteration of the migration, we listen for instructions
+ * by the source VM to perform dynamic page registrations before they
+ * can perform RDMA operations.
+ *
+ * We respond with the 'rkey'.
+ *
+ * Keep doing this until the source tells us to stop.
+ */
+static int qemu_rdma_registration_handle(QEMUFile *f, void *opaque,
+ uint64_t flags)
+{
+ RDMAControlHeader reg_resp = { .len = sizeof(RDMARegisterResult),
+ .type = RDMA_CONTROL_REGISTER_RESULT,
+ .repeat = 0,
+ };
+ RDMAControlHeader unreg_resp = { .len = 0,
+ .type = RDMA_CONTROL_UNREGISTER_FINISHED,
+ .repeat = 0,
+ };
+ RDMAControlHeader blocks = { .type = RDMA_CONTROL_RAM_BLOCKS_RESULT,
+ .repeat = 1 };
+ QEMUFileRDMA *rfile = opaque;
+ RDMAContext *rdma = rfile->rdma;
+ RDMALocalBlocks *local = &rdma->local_ram_blocks;
+ RDMAControlHeader head;
+ RDMARegister *reg, *registers;
+ RDMACompress *comp;
+ RDMARegisterResult *reg_result;
+ static RDMARegisterResult results[RDMA_CONTROL_MAX_COMMANDS_PER_MESSAGE];
+ RDMALocalBlock *block;
+ void *host_addr;
+ int ret = 0;
+ int idx = 0;
+ int count = 0;
+ int i = 0;
+
+ CHECK_ERROR_STATE();
+
+ do {
+ DDDPRINTF("Waiting for next request %" PRIu64 "...\n", flags);
+
+ ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_NONE);
+
+ if (ret < 0) {
+ break;
+ }
+
+ if (head.repeat > RDMA_CONTROL_MAX_COMMANDS_PER_MESSAGE) {
+ fprintf(stderr, "rdma: Too many requests in this message (%d)."
+ "Bailing.\n", head.repeat);
+ ret = -EIO;
+ break;
+ }
+
+ switch (head.type) {
+ case RDMA_CONTROL_COMPRESS:
+ comp = (RDMACompress *) rdma->wr_data[idx].control_curr;
+ network_to_compress(comp);
+
+ DDPRINTF("Zapping zero chunk: %" PRId64
+ " bytes, index %d, offset %" PRId64 "\n",
+ comp->length, comp->block_idx, comp->offset);
+ block = &(rdma->local_ram_blocks.block[comp->block_idx]);
+
+ host_addr = block->local_host_addr +
+ (comp->offset - block->offset);
+
+ ram_handle_compressed(host_addr, comp->value, comp->length);
+ break;
+
+ case RDMA_CONTROL_REGISTER_FINISHED:
+ DDDPRINTF("Current registrations complete.\n");
+ goto out;
+
+ case RDMA_CONTROL_RAM_BLOCKS_REQUEST:
+ DPRINTF("Initial setup info requested.\n");
+
+ if (rdma->pin_all) {
+ ret = qemu_rdma_reg_whole_ram_blocks(rdma);
+ if (ret) {
+ fprintf(stderr, "rdma migration: error dest "
+ "registering ram blocks!\n");
+ goto out;
+ }
+ }
+
+ /*
+ * Dest uses this to prepare to transmit the RAMBlock descriptions
+ * to the source VM after connection setup.
+ * Both sides use the "remote" structure to communicate and update
+ * their "local" descriptions with what was sent.
+ */
+ for (i = 0; i < local->nb_blocks; i++) {
+ rdma->block[i].remote_host_addr =
+ (uint64_t)(local->block[i].local_host_addr);
+
+ if (rdma->pin_all) {
+ rdma->block[i].remote_rkey = local->block[i].mr->rkey;
+ }
+
+ rdma->block[i].offset = local->block[i].offset;
+ rdma->block[i].length = local->block[i].length;
+
+ remote_block_to_network(&rdma->block[i]);
+ }
+
+ blocks.len = rdma->local_ram_blocks.nb_blocks
+ * sizeof(RDMARemoteBlock);
+
+
+ ret = qemu_rdma_post_send_control(rdma,
+ (uint8_t *) rdma->block, &blocks);
+
+ if (ret < 0) {
+ fprintf(stderr, "rdma migration: error sending remote info!\n");
+ goto out;
+ }
+
+ break;
+ case RDMA_CONTROL_REGISTER_REQUEST:
+ DDPRINTF("There are %d registration requests\n", head.repeat);
+
+ reg_resp.repeat = head.repeat;
+ registers = (RDMARegister *) rdma->wr_data[idx].control_curr;
+
+ for (count = 0; count < head.repeat; count++) {
+ uint64_t chunk;
+ uint8_t *chunk_start, *chunk_end;
+
+ reg = &registers[count];
+ network_to_register(reg);
+
+ reg_result = &results[count];
+
+ DDPRINTF("Registration request (%d): index %d, current_addr %"
+ PRIu64 " chunks: %" PRIu64 "\n", count,
+ reg->current_index, reg->key.current_addr, reg->chunks);
+
+ block = &(rdma->local_ram_blocks.block[reg->current_index]);
+ if (block->is_ram_block) {
+ host_addr = (block->local_host_addr +
+ (reg->key.current_addr - block->offset));
+ chunk = ram_chunk_index(block->local_host_addr,
+ (uint8_t *) host_addr);
+ } else {
+ chunk = reg->key.chunk;
+ host_addr = block->local_host_addr +
+ (reg->key.chunk * (1UL << RDMA_REG_CHUNK_SHIFT));
+ }
+ chunk_start = ram_chunk_start(block, chunk);
+ chunk_end = ram_chunk_end(block, chunk + reg->chunks);
+ if (qemu_rdma_register_and_get_keys(rdma, block,
+ (uint8_t *)host_addr, NULL, &reg_result->rkey,
+ chunk, chunk_start, chunk_end)) {
+ fprintf(stderr, "cannot get rkey!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ reg_result->host_addr = (uint64_t) block->local_host_addr;
+
+ DDPRINTF("Registered rkey for this request: %x\n",
+ reg_result->rkey);
+
+ result_to_network(reg_result);
+ }
+
+ ret = qemu_rdma_post_send_control(rdma,
+ (uint8_t *) results, &reg_resp);
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to send control buffer!\n");
+ goto out;
+ }
+ break;
+ case RDMA_CONTROL_UNREGISTER_REQUEST:
+ DDPRINTF("There are %d unregistration requests\n", head.repeat);
+ unreg_resp.repeat = head.repeat;
+ registers = (RDMARegister *) rdma->wr_data[idx].control_curr;
+
+ for (count = 0; count < head.repeat; count++) {
+ reg = &registers[count];
+ network_to_register(reg);
+
+ DDPRINTF("Unregistration request (%d): "
+ " index %d, chunk %" PRIu64 "\n",
+ count, reg->current_index, reg->key.chunk);
+
+ block = &(rdma->local_ram_blocks.block[reg->current_index]);
+
+ ret = ibv_dereg_mr(block->pmr[reg->key.chunk]);
+ block->pmr[reg->key.chunk] = NULL;
+
+ if (ret != 0) {
+ perror("rdma unregistration chunk failed");
+ ret = -ret;
+ goto out;
+ }
+
+ rdma->total_registrations--;
+
+ DDPRINTF("Unregistered chunk %" PRIu64 " successfully.\n",
+ reg->key.chunk);
+ }
+
+ ret = qemu_rdma_post_send_control(rdma, NULL, &unreg_resp);
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to send control buffer!\n");
+ goto out;
+ }
+ break;
+ case RDMA_CONTROL_REGISTER_RESULT:
+ fprintf(stderr, "Invalid RESULT message at dest.\n");
+ ret = -EIO;
+ goto out;
+ default:
+ fprintf(stderr, "Unknown control message %s\n",
+ control_desc[head.type]);
+ ret = -EIO;
+ goto out;
+ }
+ } while (1);
+out:
+ if (ret < 0) {
+ rdma->error_state = ret;
+ }
+ return ret;
+}
+
+static int qemu_rdma_registration_start(QEMUFile *f, void *opaque,
+ uint64_t flags)
+{
+ QEMUFileRDMA *rfile = opaque;
+ RDMAContext *rdma = rfile->rdma;
+
+ CHECK_ERROR_STATE();
+
+ DDDPRINTF("start section: %" PRIu64 "\n", flags);
+ qemu_put_be64(f, RAM_SAVE_FLAG_HOOK);
+ qemu_fflush(f);
+
+ return 0;
+}
+
+/*
+ * Inform dest that dynamic registrations are done for now.
+ * First, flush writes, if any.
+ */
+static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
+ uint64_t flags)
+{
+ Error *local_err = NULL, **errp = &local_err;
+ QEMUFileRDMA *rfile = opaque;
+ RDMAContext *rdma = rfile->rdma;
+ RDMAControlHeader head = { .len = 0, .repeat = 1 };
+ int ret = 0;
+
+ CHECK_ERROR_STATE();
+
+ qemu_fflush(f);
+ ret = qemu_rdma_drain_cq(f, rdma);
+
+ if (ret < 0) {
+ goto err;
+ }
+
+ if (flags == RAM_CONTROL_SETUP) {
+ RDMAControlHeader resp = {.type = RDMA_CONTROL_RAM_BLOCKS_RESULT };
+ RDMALocalBlocks *local = &rdma->local_ram_blocks;
+ int reg_result_idx, i, j, nb_remote_blocks;
+
+ head.type = RDMA_CONTROL_RAM_BLOCKS_REQUEST;
+ DPRINTF("Sending registration setup for ram blocks...\n");
+
+ /*
+ * Make sure that we parallelize the pinning on both sides.
+ * For very large guests, doing this serially takes a really
+ * long time, so we have to 'interleave' the pinning locally
+ * with the control messages by performing the pinning on this
+ * side before we receive the control response from the other
+ * side that the pinning has completed.
+ */
+ ret = qemu_rdma_exchange_send(rdma, &head, NULL, &resp,
+ &reg_result_idx, rdma->pin_all ?
+ qemu_rdma_reg_whole_ram_blocks : NULL);
+ if (ret < 0) {
+ ERROR(errp, "receiving remote info!\n");
+ return ret;
+ }
+
+ qemu_rdma_move_header(rdma, reg_result_idx, &resp);
+ memcpy(rdma->block,
+ rdma->wr_data[reg_result_idx].control_curr, resp.len);
+
+ nb_remote_blocks = resp.len / sizeof(RDMARemoteBlock);
+
+ /*
+ * The protocol uses two different sets of rkeys (mutually exclusive):
+ * 1. One key to represent the virtual address of the entire ram block.
+ * (dynamic chunk registration disabled - pin everything with one rkey.)
+ * 2. One to represent individual chunks within a ram block.
+ * (dynamic chunk registration enabled - pin individual chunks.)
+ *
+ * Once the capability is successfully negotiated, the destination transmits
+ * the keys to use (or sends them later) including the virtual addresses
+ * and then propagates the remote ram block descriptions to his local copy.
+ */
+
+ if (local->nb_blocks != nb_remote_blocks) {
+ ERROR(errp, "ram blocks mismatch #1! "
+ "Your QEMU command line parameters are probably "
+ "not identical on both the source and destination.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < nb_remote_blocks; i++) {
+ network_to_remote_block(&rdma->block[i]);
+
+ /* search local ram blocks */
+ for (j = 0; j < local->nb_blocks; j++) {
+ if (rdma->block[i].offset != local->block[j].offset) {
+ continue;
+ }
+
+ if (rdma->block[i].length != local->block[j].length) {
+ ERROR(errp, "ram blocks mismatch #2! "
+ "Your QEMU command line parameters are probably "
+ "not identical on both the source and destination.\n");
+ return -EINVAL;
+ }
+ local->block[j].remote_host_addr =
+ rdma->block[i].remote_host_addr;
+ local->block[j].remote_rkey = rdma->block[i].remote_rkey;
+ break;
+ }
+
+ if (j >= local->nb_blocks) {
+ ERROR(errp, "ram blocks mismatch #3! "
+ "Your QEMU command line parameters are probably "
+ "not identical on both the source and destination.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ DDDPRINTF("Sending registration finish %" PRIu64 "...\n", flags);
+
+ head.type = RDMA_CONTROL_REGISTER_FINISHED;
+ ret = qemu_rdma_exchange_send(rdma, &head, NULL, NULL, NULL, NULL);
+
+ if (ret < 0) {
+ goto err;
+ }
+
+ return 0;
+err:
+ rdma->error_state = ret;
+ return ret;
+}
+
+static int qemu_rdma_get_fd(void *opaque)
+{
+ QEMUFileRDMA *rfile = opaque;
+ RDMAContext *rdma = rfile->rdma;
+
+ return rdma->comp_channel->fd;
+}
+
+const QEMUFileOps rdma_read_ops = {
+ .get_buffer = qemu_rdma_get_buffer,
+ .get_fd = qemu_rdma_get_fd,
+ .close = qemu_rdma_close,
+ .hook_ram_load = qemu_rdma_registration_handle,
+};
+
+const QEMUFileOps rdma_write_ops = {
+ .put_buffer = qemu_rdma_put_buffer,
+ .close = qemu_rdma_close,
+ .before_ram_iterate = qemu_rdma_registration_start,
+ .after_ram_iterate = qemu_rdma_registration_stop,
+ .save_page = qemu_rdma_save_page,
+};
+
+static void *qemu_fopen_rdma(RDMAContext *rdma, const char *mode)
+{
+ QEMUFileRDMA *r = g_malloc0(sizeof(QEMUFileRDMA));
+
+ if (qemu_file_mode_is_not_valid(mode)) {
+ return NULL;
+ }
+
+ r->rdma = rdma;
+
+ if (mode[0] == 'w') {
+ r->file = qemu_fopen_ops(r, &rdma_write_ops);
+ } else {
+ r->file = qemu_fopen_ops(r, &rdma_read_ops);
+ }
+
+ return r->file;
+}
+
+static void rdma_accept_incoming_migration(void *opaque)
+{
+ RDMAContext *rdma = opaque;
+ int ret;
+ QEMUFile *f;
+ Error *local_err = NULL, **errp = &local_err;
+
+ DPRINTF("Accepting rdma connection...\n");
+ ret = qemu_rdma_accept(rdma);
+
+ if (ret) {
+ ERROR(errp, "RDMA Migration initialization failed!\n");
+ return;
+ }
+
+ DPRINTF("Accepted migration\n");
+
+ f = qemu_fopen_rdma(rdma, "rb");
+ if (f == NULL) {
+ ERROR(errp, "could not qemu_fopen_rdma!\n");
+ qemu_rdma_cleanup(rdma);
+ return;
+ }
+
+ rdma->migration_started_on_destination = 1;
+ process_incoming_migration(f);
+}
+
+void rdma_start_incoming_migration(const char *host_port, Error **errp)
+{
+ int ret;
+ RDMAContext *rdma;
+ Error *local_err = NULL;
+
+ DPRINTF("Starting RDMA-based incoming migration\n");
+ rdma = qemu_rdma_data_init(host_port, &local_err);
+
+ if (rdma == NULL) {
+ goto err;
+ }
+
+ ret = qemu_rdma_dest_init(rdma, &local_err);
+
+ if (ret) {
+ goto err;
+ }
+
+ DPRINTF("qemu_rdma_dest_init success\n");
+
+ ret = rdma_listen(rdma->listen_id, 5);
+
+ if (ret) {
+ ERROR(errp, "listening on socket!\n");
+ goto err;
+ }
+
+ DPRINTF("rdma_listen success\n");
+
+ qemu_set_fd_handler2(rdma->channel->fd, NULL,
+ rdma_accept_incoming_migration, NULL,
+ (void *)(intptr_t) rdma);
+ return;
+err:
+ error_propagate(errp, local_err);
+ g_free(rdma);
+}
+
+void rdma_start_outgoing_migration(void *opaque,
+ const char *host_port, Error **errp)
+{
+ MigrationState *s = opaque;
+ Error *local_err = NULL, **temp = &local_err;
+ RDMAContext *rdma = qemu_rdma_data_init(host_port, &local_err);
+ int ret = 0;
+
+ if (rdma == NULL) {
+ ERROR(temp, "Failed to initialize RDMA data structures! %d\n", ret);
+ goto err;
+ }
+
+ ret = qemu_rdma_source_init(rdma, &local_err,
+ s->enabled_capabilities[MIGRATION_CAPABILITY_X_RDMA_PIN_ALL]);
+
+ if (ret) {
+ goto err;
+ }
+
+ DPRINTF("qemu_rdma_source_init success\n");
+ ret = qemu_rdma_connect(rdma, &local_err);
+
+ if (ret) {
+ goto err;
+ }
+
+ DPRINTF("qemu_rdma_source_connect success\n");
+
+ s->file = qemu_fopen_rdma(rdma, "wb");
+ migrate_fd_connect(s);
+ return;
+err:
+ error_propagate(errp, local_err);
+ g_free(rdma);
+ migrate_fd_error(s);
+}
diff --git a/migration.c b/migration.c
index 0681d8e5f1..e12e7840e6 100644
--- a/migration.c
+++ b/migration.c
@@ -36,7 +36,8 @@
#endif
enum {
- MIG_STATE_ERROR,
+ MIG_STATE_ERROR = -1,
+ MIG_STATE_NONE,
MIG_STATE_SETUP,
MIG_STATE_CANCELLED,
MIG_STATE_ACTIVE,
@@ -63,7 +64,7 @@ static NotifierList migration_state_notifiers =
MigrationState *migrate_get_current(void)
{
static MigrationState current_migration = {
- .state = MIG_STATE_SETUP,
+ .state = MIG_STATE_NONE,
.bandwidth_limit = MAX_THROTTLE,
.xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE,
.mbps = -1,
@@ -78,6 +79,10 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
if (strstart(uri, "tcp:", &p))
tcp_start_incoming_migration(p, errp);
+#ifdef CONFIG_RDMA
+ else if (strstart(uri, "x-rdma:", &p))
+ rdma_start_incoming_migration(p, errp);
+#endif
#if !defined(WIN32)
else if (strstart(uri, "exec:", &p))
exec_start_incoming_migration(p, errp);
@@ -180,9 +185,14 @@ MigrationInfo *qmp_query_migrate(Error **errp)
MigrationState *s = migrate_get_current();
switch (s->state) {
- case MIG_STATE_SETUP:
+ case MIG_STATE_NONE:
/* no migration has happened ever */
break;
+ case MIG_STATE_SETUP:
+ info->has_status = true;
+ info->status = g_strdup("setup");
+ info->has_total_time = false;
+ break;
case MIG_STATE_ACTIVE:
info->has_status = true;
info->status = g_strdup("active");
@@ -191,6 +201,8 @@ MigrationInfo *qmp_query_migrate(Error **errp)
- s->total_time;
info->has_expected_downtime = true;
info->expected_downtime = s->expected_downtime;
+ info->has_setup_time = true;
+ info->setup_time = s->setup_time;
info->has_ram = true;
info->ram = g_malloc0(sizeof(*info->ram));
@@ -222,6 +234,8 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->total_time = s->total_time;
info->has_downtime = true;
info->downtime = s->downtime;
+ info->has_setup_time = true;
+ info->setup_time = s->setup_time;
info->has_ram = true;
info->ram = g_malloc0(sizeof(*info->ram));
@@ -253,7 +267,7 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
MigrationState *s = migrate_get_current();
MigrationCapabilityStatusList *cap;
- if (s->state == MIG_STATE_ACTIVE) {
+ if (s->state == MIG_STATE_ACTIVE || s->state == MIG_STATE_SETUP) {
error_set(errp, QERR_MIGRATION_ACTIVE);
return;
}
@@ -291,9 +305,9 @@ static void migrate_fd_cleanup(void *opaque)
notifier_list_notify(&migration_state_notifiers, s);
}
-static void migrate_finish_set_state(MigrationState *s, int new_state)
+static void migrate_set_state(MigrationState *s, int old_state, int new_state)
{
- if (atomic_cmpxchg(&s->state, MIG_STATE_ACTIVE, new_state) == new_state) {
+ if (atomic_cmpxchg(&s->state, old_state, new_state) == new_state) {
trace_migrate_set_state(new_state);
}
}
@@ -311,7 +325,7 @@ static void migrate_fd_cancel(MigrationState *s)
{
DPRINTF("cancelling migration\n");
- migrate_finish_set_state(s, MIG_STATE_CANCELLED);
+ migrate_set_state(s, s->state, MIG_STATE_CANCELLED);
}
void add_migration_state_change_notifier(Notifier *notify)
@@ -388,7 +402,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
params.blk = blk;
params.shared = inc;
- if (s->state == MIG_STATE_ACTIVE) {
+ if (s->state == MIG_STATE_ACTIVE || s->state == MIG_STATE_SETUP) {
error_set(errp, QERR_MIGRATION_ACTIVE);
return;
}
@@ -406,6 +420,10 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
if (strstart(uri, "tcp:", &p)) {
tcp_start_outgoing_migration(s, p, &local_err);
+#ifdef CONFIG_RDMA
+ } else if (strstart(uri, "x-rdma:", &p)) {
+ rdma_start_outgoing_migration(s, p, &local_err);
+#endif
#if !defined(WIN32)
} else if (strstart(uri, "exec:", &p)) {
exec_start_outgoing_migration(s, p, &local_err);
@@ -484,6 +502,24 @@ bool migrate_rdma_pin_all(void)
return s->enabled_capabilities[MIGRATION_CAPABILITY_X_RDMA_PIN_ALL];
}
+bool migrate_auto_converge(void)
+{
+ MigrationState *s;
+
+ s = migrate_get_current();
+
+ return s->enabled_capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE];
+}
+
+bool migrate_zero_blocks(void)
+{
+ MigrationState *s;
+
+ s = migrate_get_current();
+
+ return s->enabled_capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS];
+}
+
int migrate_use_xbzrle(void)
{
MigrationState *s;
@@ -508,6 +544,7 @@ static void *migration_thread(void *opaque)
{
MigrationState *s = opaque;
int64_t initial_time = qemu_get_clock_ms(rt_clock);
+ int64_t setup_start = qemu_get_clock_ms(host_clock);
int64_t initial_bytes = 0;
int64_t max_size = 0;
int64_t start_time = initial_time;
@@ -516,6 +553,11 @@ static void *migration_thread(void *opaque)
DPRINTF("beginning savevm\n");
qemu_savevm_state_begin(s->file, &s->params);
+ s->setup_time = qemu_get_clock_ms(host_clock) - setup_start;
+ migrate_set_state(s, MIG_STATE_SETUP, MIG_STATE_ACTIVE);
+
+ DPRINTF("setup complete\n");
+
while (s->state == MIG_STATE_ACTIVE) {
int64_t current_time;
uint64_t pending_size;
@@ -543,19 +585,19 @@ static void *migration_thread(void *opaque)
qemu_mutex_unlock_iothread();
if (ret < 0) {
- migrate_finish_set_state(s, MIG_STATE_ERROR);
+ migrate_set_state(s, MIG_STATE_ACTIVE, MIG_STATE_ERROR);
break;
}
if (!qemu_file_get_error(s->file)) {
- migrate_finish_set_state(s, MIG_STATE_COMPLETED);
+ migrate_set_state(s, MIG_STATE_ACTIVE, MIG_STATE_COMPLETED);
break;
}
}
}
if (qemu_file_get_error(s->file)) {
- migrate_finish_set_state(s, MIG_STATE_ERROR);
+ migrate_set_state(s, MIG_STATE_ACTIVE, MIG_STATE_ERROR);
break;
}
current_time = qemu_get_clock_ms(rt_clock);
@@ -606,8 +648,8 @@ static void *migration_thread(void *opaque)
void migrate_fd_connect(MigrationState *s)
{
- s->state = MIG_STATE_ACTIVE;
- trace_migrate_set_state(MIG_STATE_ACTIVE);
+ s->state = MIG_STATE_SETUP;
+ trace_migrate_set_state(MIG_STATE_SETUP);
/* This is a best 1st approximation. ns to ms */
s->expected_downtime = max_downtime/1000000;
diff --git a/monitor.c b/monitor.c
index 2ba7876b56..5dc0aa97f5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -189,6 +189,7 @@ struct Monitor {
int suspend_cnt;
bool skip_flush;
QString *outbuf;
+ guint watch;
ReadLineState *rs;
MonitorControl *mc;
CPUState *mon_cpu;
@@ -263,7 +264,10 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond,
void *opaque)
{
- monitor_flush(opaque);
+ Monitor *mon = opaque;
+
+ mon->watch = 0;
+ monitor_flush(mon);
return FALSE;
}
@@ -294,7 +298,10 @@ void monitor_flush(Monitor *mon)
QDECREF(mon->outbuf);
mon->outbuf = tmp;
}
- qemu_chr_fe_add_watch(mon->chr, G_IO_OUT, monitor_unblocked, mon);
+ if (mon->watch == 0) {
+ mon->watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT,
+ monitor_unblocked, mon);
+ }
}
}
@@ -490,6 +497,7 @@ static const char *monitor_event_names[] = {
[QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
[QEVENT_DEVICE_DELETED] = "DEVICE_DELETED",
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
+ [QEVENT_NIC_RX_FILTER_CHANGED] = "NIC_RX_FILTER_CHANGED",
[QEVENT_SUSPEND] = "SUSPEND",
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
[QEVENT_WAKEUP] = "WAKEUP",
@@ -1156,7 +1164,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
cpu_physical_memory_read(addr, buf, l);
} else {
env = mon_get_cpu();
- if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) {
+ if (cpu_memory_rw_debug(ENV_GET_CPU(env), addr, buf, l, 0) < 0) {
monitor_printf(mon, " Cannot access memory\n");
break;
}
diff --git a/net/net.c b/net/net.c
index 43a74e43ae..c0d61bf78b 100644
--- a/net/net.c
+++ b/net/net.c
@@ -961,6 +961,54 @@ void print_net_client(Monitor *mon, NetClientState *nc)
nc->info_str);
}
+RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
+ Error **errp)
+{
+ NetClientState *nc;
+ RxFilterInfoList *filter_list = NULL, *last_entry = NULL;
+
+ QTAILQ_FOREACH(nc, &net_clients, next) {
+ RxFilterInfoList *entry;
+ RxFilterInfo *info;
+
+ if (has_name && strcmp(nc->name, name) != 0) {
+ continue;
+ }
+
+ /* only query rx-filter information of NIC */
+ if (nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC) {
+ if (has_name) {
+ error_setg(errp, "net client(%s) isn't a NIC", name);
+ break;
+ }
+ continue;
+ }
+
+ if (nc->info->query_rx_filter) {
+ info = nc->info->query_rx_filter(nc);
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+
+ if (!filter_list) {
+ filter_list = entry;
+ } else {
+ last_entry->next = entry;
+ }
+ last_entry = entry;
+ } else if (has_name) {
+ error_setg(errp, "net client(%s) doesn't support"
+ " rx-filter querying", name);
+ break;
+ }
+ }
+
+ if (filter_list == NULL && !error_is_set(errp) && has_name) {
+ error_setg(errp, "invalid net client name: %s", name);
+ }
+
+ return filter_list;
+}
+
void do_info_network(Monitor *mon, const QDict *qdict)
{
NetClientState *nc, *peer;
diff --git a/pc-bios/README b/pc-bios/README
index 030d92a049..53b52894f7 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -40,4 +40,4 @@
git://repo.or.cz/s390-tools.git
- The sources for the Alpha palcode image is available from:
- git://repo.or.cz/qemu-palcode.git
+ git://github.com/rth7680/qemu-palcode.git
diff --git a/pc-bios/acpi-dsdt.aml b/pc-bios/acpi-dsdt.aml
index 75dfd1e310..48dbe3242c 100644
--- a/pc-bios/acpi-dsdt.aml
+++ b/pc-bios/acpi-dsdt.aml
Binary files differ
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index c2a19b8930..cccc487814 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
diff --git a/pc-bios/palcode-clipper b/pc-bios/palcode-clipper
index a92372c107..9956340cd1 100755
--- a/pc-bios/palcode-clipper
+++ b/pc-bios/palcode-clipper
Binary files differ
diff --git a/pc-bios/q35-acpi-dsdt.aml b/pc-bios/q35-acpi-dsdt.aml
index cf7b085762..91ab67cada 100644
--- a/pc-bios/q35-acpi-dsdt.aml
+++ b/pc-bios/q35-acpi-dsdt.aml
Binary files differ
diff --git a/po/Makefile b/po/Makefile
index 60ccd7d3bb..705166e2d3 100644
--- a/po/Makefile
+++ b/po/Makefile
@@ -1,20 +1,23 @@
# This makefile is very special as it's meant to build as part of the build
# process and also within the source tree to update the translation files.
-VERSION=$(shell cat ../VERSION)
-SRCS=$(filter-out messages.po,$(wildcard *.po))
-OBJS=$(patsubst %.po,%.mo,$(SRCS))
-
+# Set SRC_PATH for in-tree builds without configuration.
SRC_PATH=..
-include ../config-host.mak
+include $(SRC_PATH)/rules.mak
+
+PO_PATH=$(SRC_PATH)/po
+
+VERSION=$(shell cat $(SRC_PATH)/VERSION)
+SRCS=$(filter-out $(PO_PATH)/messages.po,$(wildcard $(PO_PATH)/*.po))
+OBJS=$(patsubst $(PO_PATH)/%.po,%.mo,$(SRCS))
-vpath %.po $(SRC_PATH)/po
+vpath %.po $(PO_PATH)
all:
- @echo Use 'make update' to update translation files
- @echo or us 'make build' or 'make install' to build and install
- @echo the translation files
+ @echo "Use 'make update' to update translation files or use 'make build'"
+ @echo "or 'make install' to build and install the translation files."
update: $(SRCS)
@@ -31,12 +34,16 @@ install: $(OBJS)
done
%.mo: %.po
- @msgfmt -o $@ $(SRC_PATH)/po/`basename $@ .mo`.po
+ $(call quiet-command, msgfmt -o $@ $<, " GEN $@")
-messages.po: $(SRC_PATH)/ui/gtk.c
- @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=$(VERSION) --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $<
+$(PO_PATH)/messages.po: $(SRC_PATH)/ui/gtk.c
+ $(call quiet-command, cd $(SRC_PATH) && \
+ (xgettext -o - --from-code=UTF-8 --foreign-user \
+ --package-name=QEMU --package-version=$(VERSION) \
+ --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C ui/gtk.c | \
+ sed -e s/CHARSET/UTF-8/) >$@, " GEN $@")
-%.po: messages.po
- @msgmerge $@ $< > $@.bak && mv $@.bak $@
+$(PO_PATH)/%.po: $(PO_PATH)/messages.po
+ $(call quiet-command, msgmerge -q $@ $< > $@.bak && mv $@.bak $@, " GEN $@")
.PHONY: clean all
diff --git a/qapi-schema.json b/qapi-schema.json
index cf57783caf..f82d829fdc 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -578,6 +578,12 @@
# expected downtime in milliseconds for the guest in last walk
# of the dirty bitmap. (since 1.3)
#
+# @setup-time: #optional amount of setup time in milliseconds _before_ the
+# iterations begin but _after_ the QMP command is issued. This is designed
+# to provide an accounting of any activities (such as RDMA pinning) which
+# may be expensive, but do not actually occur during the iterative
+# migration rounds themselves. (since 1.6)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
@@ -586,7 +592,8 @@
'*xbzrle-cache': 'XBZRLECacheStats',
'*total-time': 'int',
'*expected-downtime': 'int',
- '*downtime': 'int'} }
+ '*downtime': 'int',
+ '*setup-time': 'int'} }
##
# @query-migrate
@@ -613,10 +620,19 @@
# Disabled by default. Experimental: may (or may not) be renamed after
# further testing is complete. (since 1.6)
#
+# @zero-blocks: During storage migration encode blocks of zeroes efficiently. This
+# essentially saves 1MB of zeroes per block on the wire. Enabling requires
+# source and target VM to support this feature. To enable it is sufficient
+# to enable the capability on the source VM. The feature is disabled by
+# default. (since 1.6)
+#
+# @auto-converge: If enabled, QEMU will automatically throttle down the guest
+# to speed up convergence of RAM migration. (since 1.6)
+#
# Since: 1.2
##
{ 'enum': 'MigrationCapability',
- 'data': ['xbzrle', 'x-rdma-pin-all'] }
+ 'data': ['xbzrle', 'x-rdma-pin-all', 'auto-converge', 'zero-blocks'] }
##
# @MigrationCapabilityStatus
@@ -3679,3 +3695,79 @@
'*cpuid-input-ecx': 'int',
'cpuid-register': 'X86CPURegister32',
'features': 'int' } }
+
+##
+# @RxState:
+#
+# Packets receiving state
+#
+# @normal: filter assigned packets according to the mac-table
+#
+# @none: don't receive any assigned packet
+#
+# @all: receive all assigned packets
+#
+# Since: 1.6
+##
+{ 'enum': 'RxState', 'data': [ 'normal', 'none', 'all' ] }
+
+##
+# @RxFilterInfo:
+#
+# Rx-filter information for a NIC.
+#
+# @name: net client name
+#
+# @promiscuous: whether promiscuous mode is enabled
+#
+# @multicast: multicast receive state
+#
+# @unicast: unicast receive state
+#
+# @broadcast-allowed: whether to receive broadcast
+#
+# @multicast-overflow: multicast table is overflowed or not
+#
+# @unicast-overflow: unicast table is overflowed or not
+#
+# @main-mac: the main macaddr string
+#
+# @vlan-table: a list of active vlan id
+#
+# @unicast-table: a list of unicast macaddr string
+#
+# @multicast-table: a list of multicast macaddr string
+#
+# Since 1.6
+##
+
+{ 'type': 'RxFilterInfo',
+ 'data': {
+ 'name': 'str',
+ 'promiscuous': 'bool',
+ 'multicast': 'RxState',
+ 'unicast': 'RxState',
+ 'broadcast-allowed': 'bool',
+ 'multicast-overflow': 'bool',
+ 'unicast-overflow': 'bool',
+ 'main-mac': 'str',
+ 'vlan-table': ['int'],
+ 'unicast-table': ['str'],
+ 'multicast-table': ['str'] }}
+
+##
+# @query-rx-filter:
+#
+# Return rx-filter information for all NICs (or for the given NIC).
+#
+# @name: #optional net client name
+#
+# Returns: list of @RxFilterInfo for all NICs (or for the given NIC).
+# Returns an error if the given @name doesn't exist, or given
+# NIC doesn't support rx-filter querying, or given net client
+# isn't a NIC.
+#
+# Since: 1.6
+##
+{ 'command': 'query-rx-filter', 'data': { '*name': 'str' },
+ 'returns': ['RxFilterInfo'] }
diff --git a/qemu-char.c b/qemu-char.c
index 800d6a62f9..c86ce4ba2e 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -720,35 +720,32 @@ static GIOChannel *io_channel_from_socket(int fd)
static int io_channel_send(GIOChannel *fd, const void *buf, size_t len)
{
- GIOStatus status;
- size_t offset;
+ size_t offset = 0;
+ GIOStatus status = G_IO_STATUS_NORMAL;
- offset = 0;
- while (offset < len) {
- gsize bytes_written;
+ while (offset < len && status == G_IO_STATUS_NORMAL) {
+ gsize bytes_written = 0;
status = g_io_channel_write_chars(fd, buf + offset, len - offset,
&bytes_written, NULL);
- if (status != G_IO_STATUS_NORMAL) {
- if (status == G_IO_STATUS_AGAIN) {
- /* If we've written any data, return a partial write. */
- if (offset) {
- break;
- }
- errno = EAGAIN;
- } else {
- errno = EINVAL;
- }
-
- return -1;
- } else if (status == G_IO_STATUS_EOF) {
- break;
- }
-
offset += bytes_written;
}
- return offset;
+ if (offset > 0) {
+ return offset;
+ }
+ switch (status) {
+ case G_IO_STATUS_NORMAL:
+ g_assert(len == 0);
+ return 0;
+ case G_IO_STATUS_AGAIN:
+ errno = EAGAIN;
+ return -1;
+ default:
+ break;
+ }
+ errno = EINVAL;
+ return -1;
}
#ifndef _WIN32
diff --git a/qemu-options.hx b/qemu-options.hx
index 4e98b4f483..2dbfd42a8c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2493,8 +2493,8 @@ listening on port 4444 would be:
@table @code
@item -serial mon:telnet::4444,server,nowait
@end table
-When monitor is multiplexed to stdio this way, Ctrl+C will not terminate
-QEMU anymore but will be passed to the guest instead.
+When the monitor is multiplexed to stdio in this way, Ctrl+C will not terminate
+QEMU any more but will be passed to the guest instead.
@item braille
Braille device. This will use BrlAPI to display the braille output on a real
diff --git a/qemu.sasl b/qemu.sasl
index cf19cf8d07..9dc8323f1d 100644
--- a/qemu.sasl
+++ b/qemu.sasl
@@ -26,7 +26,7 @@ keytab: /etc/qemu/krb5.tab
# If using digest-md5 for username/passwds, then this is the file
# containing the passwds. Use 'saslpasswd2 -a qemu [username]'
-# to add entries, and 'sasldblistusers2 -a qemu' to browse it
+# to add entries, and 'sasldblistusers2 -f [sasldb_path]' to browse it
sasldb_path: /etc/qemu/passwd.db
diff --git a/qga/service-win32.c b/qga/service-win32.c
index 02926abb28..aef41f04f1 100644
--- a/qga/service-win32.c
+++ b/qga/service-win32.c
@@ -29,36 +29,106 @@ static int printf_win_error(const char *text)
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char *)&message, 0,
NULL);
- n = printf("%s. (Error: %d) %s", text, (int)err, message);
+ n = fprintf(stderr, "%s. (Error: %d) %s", text, (int)err, message);
LocalFree(message);
return n;
}
+/* Windows command line escaping. Based on
+ * <http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx> and
+ * <http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft%28v=vs.85%29.aspx>.
+ *
+ * The caller is responsible for initializing @buffer; prior contents are lost.
+ */
+static const char *win_escape_arg(const char *to_escape, GString *buffer)
+{
+ size_t backslash_count;
+ const char *c;
+
+ /* open with a double quote */
+ g_string_assign(buffer, "\"");
+
+ backslash_count = 0;
+ for (c = to_escape; *c != '\0'; ++c) {
+ switch (*c) {
+ case '\\':
+ /* The meaning depends on the first non-backslash character coming
+ * up.
+ */
+ ++backslash_count;
+ break;
+
+ case '"':
+ /* We must escape each pending backslash, then escape the double
+ * quote. This creates a case of "odd number of backslashes [...]
+ * followed by a double quotation mark".
+ */
+ while (backslash_count) {
+ --backslash_count;
+ g_string_append(buffer, "\\\\");
+ }
+ g_string_append(buffer, "\\\"");
+ break;
+
+ default:
+ /* Any pending backslashes are without special meaning, flush them.
+ * "Backslashes are interpreted literally, unless they immediately
+ * precede a double quotation mark."
+ */
+ while (backslash_count) {
+ --backslash_count;
+ g_string_append_c(buffer, '\\');
+ }
+ g_string_append_c(buffer, *c);
+ }
+ }
+
+ /* We're about to close with a double quote in string delimiter role.
+ * Double all pending backslashes, creating a case of "even number of
+ * backslashes [...] followed by a double quotation mark".
+ */
+ while (backslash_count) {
+ --backslash_count;
+ g_string_append(buffer, "\\\\");
+ }
+ g_string_append_c(buffer, '"');
+
+ return buffer->str;
+}
+
int ga_install_service(const char *path, const char *logfile,
const char *state_dir)
{
+ int ret = EXIT_FAILURE;
SC_HANDLE manager;
SC_HANDLE service;
TCHAR module_fname[MAX_PATH];
+ GString *esc;
GString *cmdline;
+ SERVICE_DESCRIPTION desc = { (char *)QGA_SERVICE_DESCRIPTION };
if (GetModuleFileName(NULL, module_fname, MAX_PATH) == 0) {
printf_win_error("No full path to service's executable");
return EXIT_FAILURE;
}
- cmdline = g_string_new(module_fname);
- g_string_append(cmdline, " -d");
+ esc = g_string_new("");
+ cmdline = g_string_new("");
+
+ g_string_append_printf(cmdline, "%s -d",
+ win_escape_arg(module_fname, esc));
if (path) {
- g_string_append_printf(cmdline, " -p %s", path);
+ g_string_append_printf(cmdline, " -p %s", win_escape_arg(path, esc));
}
if (logfile) {
- g_string_append_printf(cmdline, " -l %s -v", logfile);
+ g_string_append_printf(cmdline, " -l %s -v",
+ win_escape_arg(logfile, esc));
}
if (state_dir) {
- g_string_append_printf(cmdline, " -t %s", state_dir);
+ g_string_append_printf(cmdline, " -t %s",
+ win_escape_arg(state_dir, esc));
}
g_debug("service's cmdline: %s", cmdline->str);
@@ -66,28 +136,29 @@ int ga_install_service(const char *path, const char *logfile,
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (manager == NULL) {
printf_win_error("No handle to service control manager");
- g_string_free(cmdline, TRUE);
- return EXIT_FAILURE;
+ goto out_strings;
}
service = CreateService(manager, QGA_SERVICE_NAME, QGA_SERVICE_DISPLAY_NAME,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL, cmdline->str, NULL, NULL, NULL, NULL, NULL);
-
- if (service) {
- SERVICE_DESCRIPTION desc = { (char *)QGA_SERVICE_DESCRIPTION };
- ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &desc);
-
- printf("Service was installed successfully.\n");
- } else {
+ if (service == NULL) {
printf_win_error("Failed to install service");
+ goto out_manager;
}
+ ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &desc);
+ fprintf(stderr, "Service was installed successfully.\n");
+ ret = EXIT_SUCCESS;
CloseServiceHandle(service);
+
+out_manager:
CloseServiceHandle(manager);
+out_strings:
g_string_free(cmdline, TRUE);
- return (service == NULL);
+ g_string_free(esc, TRUE);
+ return ret;
}
int ga_uninstall_service(void)
@@ -111,7 +182,7 @@ int ga_uninstall_service(void)
if (DeleteService(service) == FALSE) {
printf_win_error("Failed to delete service");
} else {
- printf("Service was deleted successfully.\n");
+ fprintf(stderr, "Service was deleted successfully.\n");
}
CloseServiceHandle(service);
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e075df423a..65a9e26423 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -346,7 +346,8 @@ Send keys to VM.
Arguments:
keys array:
- - "key": key sequence (a json-array of key enum values)
+ - "key": key sequence (a json-array of key union values,
+ union can be number or qcode enum)
- hold-time: time to delay key up events, milliseconds. Defaults to 100
(json-int, optional)
@@ -354,7 +355,9 @@ keys array:
Example:
-> { "execute": "send-key",
- "arguments": { 'keys': [ 'ctrl', 'alt', 'delete' ] } }
+ "arguments": { "keys": [ { "type": "qcode", "data": "ctrl" },
+ { "type": "qcode", "data": "alt" },
+ { "type": "qcode", "data": "delete" } ] } }
<- { "return": {} }
EQMP
@@ -3047,3 +3050,66 @@ Example:
<- { "return": {} }
EQMP
+ {
+ .name = "query-rx-filter",
+ .args_type = "name:s?",
+ .mhandler.cmd_new = qmp_marshal_input_query_rx_filter,
+ },
+
+SQMP
+query-rx-filter
+---------------
+
+Show rx-filter information.
+
+Returns a json-array of rx-filter information for all NICs (or for the
+given NIC), returning an error if the given NIC doesn't exist, or
+given NIC doesn't support rx-filter querying, or given net client
+isn't a NIC.
+
+The query will clear the event notification flag of each NIC, then qemu
+will start to emit event to QMP monitor.
+
+Each array entry contains the following:
+
+- "name": net client name (json-string)
+- "promiscuous": promiscuous mode is enabled (json-bool)
+- "multicast": multicast receive state (one of 'normal', 'none', 'all')
+- "unicast": unicast receive state (one of 'normal', 'none', 'all')
+- "broadcast-allowed": allow to receive broadcast (json-bool)
+- "multicast-overflow": multicast table is overflowed (json-bool)
+- "unicast-overflow": unicast table is overflowed (json-bool)
+- "main-mac": main macaddr string (json-string)
+- "vlan-table": a json-array of active vlan id
+- "unicast-table": a json-array of unicast macaddr string
+- "multicast-table": a json-array of multicast macaddr string
+
+Example:
+
+-> { "execute": "query-rx-filter", "arguments": { "name": "vnet0" } }
+<- { "return": [
+ {
+ "promiscuous": true,
+ "name": "vnet0",
+ "main-mac": "52:54:00:12:34:56",
+ "unicast": "normal",
+ "vlan-table": [
+ 4,
+ 0
+ ],
+ "unicast-table": [
+ ],
+ "multicast": "normal",
+ "multicast-overflow": false,
+ "unicast-overflow": false,
+ "multicast-table": [
+ "01:00:5e:00:00:01",
+ "33:33:00:00:00:01",
+ "33:33:ff:12:34:56"
+ ],
+ "broadcast-allowed": false
+ }
+ ]
+ }
+
+EQMP
diff --git a/qtest.c b/qtest.c
index 07a96120dc..74f1842c1e 100644
--- a/qtest.c
+++ b/qtest.c
@@ -472,7 +472,12 @@ static void qtest_event(void *opaque, int event)
switch (event) {
case CHR_EVENT_OPENED:
- qemu_system_reset(false);
+ /*
+ * We used to call qemu_system_reset() here, hoping we could
+ * use the same process for multiple tests that way. Never
+ * used. Injects an extra reset even when it's not used, and
+ * that can mess up tests, e.g. -boot once.
+ */
for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
irq_levels[i] = 0;
}
diff --git a/roms/qemu-palcode b/roms/qemu-palcode
-Subproject 7abb12f60eb3069019e9497e193733d77d8f072
+Subproject c87a92639b28ac42bc8f6c67443543b405dc479
diff --git a/roms/seabios b/roms/seabios
-Subproject d4f7d90f47462b4e8836899adc5060fbde5253e
+Subproject c02c219cd79299a0a153ecf862f0e301a057f2c
diff --git a/savevm.c b/savevm.c
index e0491e7580..03fc4d93bf 100644
--- a/savevm.c
+++ b/savevm.c
@@ -662,7 +662,7 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
offset, size, bytes_sent);
if (ret != RAM_SAVE_CONTROL_DELAYED) {
- if (*bytes_sent > 0) {
+ if (bytes_sent && *bytes_sent > 0) {
qemu_update_position(f, *bytes_sent);
} else if (ret < 0) {
qemu_file_set_error(f, ret);
diff --git a/scripts/cleanup-trace-events.pl b/scripts/cleanup-trace-events.pl
new file mode 100755
index 0000000000..cffbf165dc
--- /dev/null
+++ b/scripts/cleanup-trace-events.pl
@@ -0,0 +1,51 @@
+#!/usr/bin/perl
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# Authors:
+# Markus Armbruster <armbru@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+# Usage: cleanup-trace-events.pl trace-events
+#
+# Print cleaned up trace-events to standard output.
+
+use warnings;
+use strict;
+
+my $buf = '';
+my %seen = ();
+
+sub out {
+ print $buf;
+ $buf = '';
+ %seen = ();
+}
+
+while (<>) {
+ if (/^(disable )?([a-z_0-9]+)\(/) {
+ open GREP, '-|', 'git', 'grep', '-l', "trace_$2"
+ or die "run git grep: $!";
+ my $fname;
+ while ($fname = <GREP>) {
+ chomp $fname;
+ next if $seen{$fname} || $fname eq 'trace-events';
+ $seen{$fname} = 1;
+ $buf = "# $fname\n" . $buf;
+ }
+ unless (close GREP) {
+ die "close git grep: $!"
+ if $!;
+ next;
+ }
+ } elsif (/^# ([^ ]*\.[ch])$/) {
+ out;
+ next;
+ } elsif (!/^#|^$/) {
+ warn "unintelligible line";
+ }
+ $buf .= $_;
+}
+
+out;
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index e06332bd55..b12b6964ef 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -128,12 +128,15 @@ bool has_%(argname)s = false;
def gen_visitor_input_block(args, obj, dealloc=False):
ret = ""
+ errparg = 'errp'
+
if len(args) == 0:
return ret
push_indent()
if dealloc:
+ errparg = 'NULL'
ret += mcgen('''
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
@@ -148,22 +151,22 @@ v = qmp_input_get_visitor(mi);
for argname, argtype, optional, structured in parse_args(args):
if optional:
ret += mcgen('''
-visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
+visit_start_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
if (has_%(c_name)s) {
''',
- c_name=c_var(argname), name=argname)
+ c_name=c_var(argname), name=argname, errp=errparg)
push_indent()
ret += mcgen('''
-%(visitor)s(v, &%(c_name)s, "%(name)s", errp);
+%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
''',
c_name=c_var(argname), name=argname, argtype=argtype,
- visitor=type_visitor(argtype))
+ visitor=type_visitor(argtype), errp=errparg)
if optional:
pop_indent()
ret += mcgen('''
}
-visit_end_optional(v, errp);
-''')
+visit_end_optional(v, %(errp)s);
+''', errp=errparg)
if dealloc:
ret += mcgen('''
@@ -194,7 +197,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o
}
qmp_output_visitor_cleanup(mo);
v = qapi_dealloc_get_visitor(md);
- %(visitor)s(v, &ret_in, "unused", errp);
+ %(visitor)s(v, &ret_in, "unused", NULL);
qapi_dealloc_visitor_cleanup(md);
}
''',
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index 3f3ab095b1..b144f1ce3a 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -49,22 +49,6 @@
* free the m_ext. This is inefficient memory-wise, but who cares.
*/
-/* XXX should union some of these! */
-/* header at beginning of each mbuf: */
-struct m_hdr {
- struct mbuf *mh_next; /* Linked list of mbufs */
- struct mbuf *mh_prev;
- struct mbuf *mh_nextpkt; /* Next packet in queue/record */
- struct mbuf *mh_prevpkt; /* Flags aren't used in the output queue */
- int mh_flags; /* Misc flags */
-
- int mh_size; /* Size of data */
- struct socket *mh_so;
-
- caddr_t mh_data; /* Location of data */
- int mh_len; /* Amount of data in this mbuf */
-};
-
/*
* How much room is in the mbuf, from m_data to the end of the mbuf
*/
@@ -80,29 +64,30 @@ struct m_hdr {
#define M_TRAILINGSPACE M_FREEROOM
struct mbuf {
- struct m_hdr m_hdr;
+ /* XXX should union some of these! */
+ /* header at beginning of each mbuf: */
+ struct mbuf *m_next; /* Linked list of mbufs */
+ struct mbuf *m_prev;
+ struct mbuf *m_nextpkt; /* Next packet in queue/record */
+ struct mbuf *m_prevpkt; /* Flags aren't used in the output queue */
+ int m_flags; /* Misc flags */
+
+ int m_size; /* Size of data */
+ struct socket *m_so;
+
+ caddr_t m_data; /* Location of data */
+ int m_len; /* Amount of data in this mbuf */
+
Slirp *slirp;
bool arp_requested;
uint64_t expiration_date;
/* start of dynamic buffer area, must be last element */
- union M_dat {
- char m_dat_[1]; /* ANSI don't like 0 sized arrays */
- char *m_ext_;
- } M_dat;
+ union {
+ char m_dat[1]; /* ANSI don't like 0 sized arrays */
+ char *m_ext;
+ };
};
-#define m_next m_hdr.mh_next
-#define m_prev m_hdr.mh_prev
-#define m_nextpkt m_hdr.mh_nextpkt
-#define m_prevpkt m_hdr.mh_prevpkt
-#define m_flags m_hdr.mh_flags
-#define m_len m_hdr.mh_len
-#define m_data m_hdr.mh_data
-#define m_size m_hdr.mh_size
-#define m_dat M_dat.m_dat_
-#define m_ext M_dat.m_ext_
-#define m_so m_hdr.mh_so
-
#define ifq_prev m_prev
#define ifq_next m_next
#define ifs_prev m_prevpkt
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index e98ce1a50c..043f28fcae 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -647,7 +647,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
n4 = (laddr & 0xff);
m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
+ m->m_len += snprintf(bptr, m->m_size - m->m_len,
"ORT %d,%d,%d,%d,%d,%d\r\n%s",
n1, n2, n3, n4, n5, n6, x==7?buff:"");
return 1;
@@ -680,7 +680,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
n4 = (laddr & 0xff);
m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
+ m->m_len += snprintf(bptr, m->m_size - m->m_len,
"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
n1, n2, n3, n4, n5, n6, x==7?buff:"");
@@ -706,7 +706,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
(so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
htons(lport), SS_FACCEPTONCE)) != NULL)
- m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
+ m->m_len = snprintf(m->m_data, m->m_size, "%d",
ntohs(so->so_fport)) + 1;
return 1;
@@ -726,7 +726,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
return 1;
}
m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+ m->m_len += snprintf(bptr, m->m_size,
"DCC CHAT chat %lu %u%c\n",
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), 1);
@@ -737,7 +737,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
return 1;
}
m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+ m->m_len += snprintf(bptr, m->m_size,
"DCC SEND %s %lu %u %u%c\n", buff,
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), n1, 1);
@@ -748,7 +748,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
return 1;
}
m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+ m->m_len += snprintf(bptr, m->m_size,
"DCC MOVE %s %lu %u %u%c\n", buff,
(unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), n1, 1);
diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h
index 60125b19d5..b2eeba36f3 100644
--- a/target-alpha/cpu-qom.h
+++ b/target-alpha/cpu-qom.h
@@ -81,5 +81,6 @@ extern const struct VMStateDescription vmstate_alpha_cpu;
void alpha_cpu_do_interrupt(CPUState *cpu);
void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
index 26708055d9..c8c8c2c861 100644
--- a/target-alpha/cpu.c
+++ b/target-alpha/cpu.c
@@ -24,6 +24,13 @@
#include "migration/vmstate.h"
+static void alpha_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ AlphaCPU *cpu = ALPHA_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)
{
AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev);
@@ -263,8 +270,12 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = alpha_cpu_class_by_name;
cc->do_interrupt = alpha_cpu_do_interrupt;
cc->dump_state = alpha_cpu_dump_state;
- cpu_class_set_do_unassigned_access(cc, alpha_cpu_unassigned_access);
- device_class_set_vmsd(dc, &vmstate_alpha_cpu);
+ cc->set_pc = alpha_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->do_unassigned_access = alpha_cpu_unassigned_access;
+ cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
+ dc->vmsd = &vmstate_alpha_cpu;
+#endif
}
static const TypeInfo alpha_cpu_type_info = {
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 066f0324e2..c85dc6e575 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -515,9 +515,4 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUAlphaState *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
-}
-
#endif /* !defined (__CPU_ALPHA_H__) */
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index ff57dd6c18..fc61bb02f7 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -315,12 +315,13 @@ static int get_physical_address(CPUAlphaState *env, target_ulong addr,
return ret;
}
-hwaddr cpu_get_phys_page_debug(CPUAlphaState *env, target_ulong addr)
+hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ AlphaCPU *cpu = ALPHA_CPU(cs);
target_ulong phys;
int prot, fail;
- fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
+ fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot);
return (fail >= 0 ? -1 : phys);
}
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 3321fde916..0e425cfc08 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -114,7 +114,8 @@ DEF_HELPER_FLAGS_2(tbis, TCG_CALL_NO_RWG, void, env, i64)
DEF_HELPER_1(halt, void, i64);
-DEF_HELPER_FLAGS_0(get_time, TCG_CALL_NO_RWG, i64)
+DEF_HELPER_FLAGS_0(get_vmtime, TCG_CALL_NO_RWG, i64)
+DEF_HELPER_FLAGS_0(get_walltime, TCG_CALL_NO_RWG, i64)
DEF_HELPER_FLAGS_2(set_alarm, TCG_CALL_NO_RWG, void, env, i64)
#endif
diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c
index 339501af90..bd94597d36 100644
--- a/target-alpha/sys_helper.c
+++ b/target-alpha/sys_helper.c
@@ -70,7 +70,12 @@ void helper_halt(uint64_t restart)
}
}
-uint64_t helper_get_time(void)
+uint64_t helper_get_vmtime(void)
+{
+ return qemu_get_clock_ns(vm_clock);
+}
+
+uint64_t helper_get_walltime(void)
{
return qemu_get_clock_ns(rtc_clock);
}
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index dd7f0fbf94..0efd5595e6 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -38,7 +38,6 @@
typedef struct DisasContext DisasContext;
struct DisasContext {
struct TranslationBlock *tb;
- CPUAlphaState *env;
uint64_t pc;
int mem_idx;
@@ -46,6 +45,11 @@ struct DisasContext {
int tb_rm;
/* Current flush-to-zero setting for this TB. */
int tb_ftz;
+
+ /* implver value for this CPU. */
+ int implver;
+
+ bool singlestep_enabled;
};
/* Return values from translate_one, indicating the state of the TB.
@@ -380,7 +384,7 @@ static int use_goto_tb(DisasContext *ctx, uint64_t dest)
/* Check for the dest on the same page as the start of the TB. We
also want to suppress goto_tb in the case of single-steping and IO. */
return (((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0
- && !ctx->env->singlestep_enabled
+ && !ctx->singlestep_enabled
&& !(ctx->tb->cflags & CF_LAST_IO));
}
@@ -1634,15 +1638,19 @@ static ExitStatus gen_mfpr(int ra, int regno)
return NO_EXIT;
}
- if (regno == 250) {
- /* WALL_TIME */
+ /* Special help for VMTIME and WALLTIME. */
+ if (regno == 250 || regno == 249) {
+ void (*helper)(TCGv) = gen_helper_get_walltime;
+ if (regno == 249) {
+ helper = gen_helper_get_vmtime;
+ }
if (use_icount) {
gen_io_start();
- gen_helper_get_time(cpu_ir[ra]);
+ helper(cpu_ir[ra]);
gen_io_end();
return EXIT_PC_STALE;
} else {
- gen_helper_get_time(cpu_ir[ra]);
+ helper(cpu_ir[ra]);
return NO_EXIT;
}
}
@@ -2244,8 +2252,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x6C:
/* IMPLVER */
- if (rc != 31)
- tcg_gen_movi_i64(cpu_ir[rc], ctx->env->implver);
+ if (rc != 31) {
+ tcg_gen_movi_i64(cpu_ir[rc], ctx->implver);
+ }
break;
default:
goto invalid_opc;
@@ -3379,6 +3388,7 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu,
TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUAlphaState *env = &cpu->env;
DisasContext ctx, *ctxp = &ctx;
target_ulong pc_start;
@@ -3394,9 +3404,10 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu,
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
ctx.tb = tb;
- ctx.env = env;
ctx.pc = pc_start;
ctx.mem_idx = cpu_mmu_index(env);
+ ctx.implver = env->implver;
+ ctx.singlestep_enabled = cs->singlestep_enabled;
/* ??? Every TB begins with unset rounding mode, to be initialized on
the first fp insn of the TB. Alternately we could define a proper
@@ -3453,7 +3464,7 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu,
|| tcg_ctx.gen_opc_ptr >= gen_opc_end
|| num_insns >= max_insns
|| singlestep
- || env->singlestep_enabled)) {
+ || ctx.singlestep_enabled)) {
ret = EXIT_PC_STALE;
}
} while (ret == NO_EXIT);
@@ -3470,7 +3481,7 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu,
tcg_gen_movi_i64(cpu_pc, ctx.pc);
/* FALLTHRU */
case EXIT_PC_UPDATED:
- if (env->singlestep_enabled) {
+ if (ctx.singlestep_enabled) {
gen_excp_1(EXCP_DEBUG, 0);
} else {
tcg_gen_exit_tb(0);
diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c
index 5f01bca119..ee469c49c5 100644
--- a/target-arm/arm-semi.c
+++ b/target-arm/arm-semi.c
@@ -122,8 +122,10 @@ static target_ulong arm_semi_syscall_len;
static target_ulong syscall_err;
#endif
-static void arm_semi_cb(CPUARMState *env, target_ulong ret, target_ulong err)
+static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
#ifdef CONFIG_USER_ONLY
TaskState *ts = env->opaque;
#endif
@@ -152,12 +154,14 @@ static void arm_semi_cb(CPUARMState *env, target_ulong ret, target_ulong err)
}
}
-static void arm_semi_flen_cb(CPUARMState *env, target_ulong ret, target_ulong err)
+static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
/* The size is always stored in big-endian order, extract
the value. We assume the size always fit in 32 bits. */
uint32_t size;
- cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
+ cpu_memory_rw_debug(cs, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
env->regs[0] = be32_to_cpu(size);
#ifdef CONFIG_USER_ONLY
((TaskState *)env->opaque)->swi_errno = err;
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 48ba6054ec..02162c9aba 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -147,4 +147,6 @@ void arm_v7m_cpu_do_interrupt(CPUState *cpu);
void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+
#endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 9f1696f933..d3906a4829 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -25,6 +25,13 @@
#endif
#include "sysemu/sysemu.h"
+static void arm_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ cpu->env.regs[15] = value;
+}
+
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
{
/* Reset a single ARMCPRegInfo register */
@@ -816,7 +823,11 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = arm_cpu_class_by_name;
cc->do_interrupt = arm_cpu_do_interrupt;
cc->dump_state = arm_cpu_dump_state;
- cpu_class_set_vmsd(cc, &vmstate_arm_cpu);
+ cc->set_pc = arm_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
+ cc->vmsd = &vmstate_arm_cpu;
+#endif
}
static void cpu_register(const ARMCPUInfo *info)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c798b272a0..b2dc49413c 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -797,11 +797,6 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb)
-{
- env->regs[15] = tb->pc;
-}
-
/* Load an instruction and return it in the standard little-endian order */
static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr,
bool do_swap)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index aeae024165..b0c3ca1fbe 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1513,16 +1513,17 @@ ARMCPU *cpu_arm_init(const char *cpu_model)
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
{
+ CPUState *cs = CPU(cpu);
CPUARMState *env = &cpu->env;
if (arm_feature(env, ARM_FEATURE_NEON)) {
- gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+ gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
51, "arm-neon.xml", 0);
} else if (arm_feature(env, ARM_FEATURE_VFP3)) {
- gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+ gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
35, "arm-vfp3.xml", 0);
} else if (arm_feature(env, ARM_FEATURE_VFP)) {
- gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+ gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
19, "arm-vfp.xml", 0);
}
}
@@ -2762,17 +2763,19 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
return 1;
}
-hwaddr cpu_get_phys_page_debug(CPUARMState *env, target_ulong addr)
+hwaddr arm_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ ARMCPU *cpu = ARM_CPU(cs);
hwaddr phys_addr;
target_ulong page_size;
int prot;
int ret;
- ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot, &page_size);
+ ret = get_phys_addr(&cpu->env, addr, 0, 0, &phys_addr, &prot, &page_size);
- if (ret != 0)
+ if (ret != 0) {
return -1;
+ }
return phys_addr;
}
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 7b50c8c308..6db4c50df4 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -9911,6 +9911,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUARMState *env = &cpu->env;
DisasContext dc1, *dc = &dc1;
CPUBreakpoint *bp;
@@ -9930,7 +9931,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
- dc->singlestep_enabled = env->singlestep_enabled;
+ dc->singlestep_enabled = cs->singlestep_enabled;
dc->condjmp = 0;
dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
@@ -10080,7 +10081,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
* ensures prefetch aborts occur at the right place. */
num_insns ++;
} while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
- !env->singlestep_enabled &&
+ !cs->singlestep_enabled &&
!singlestep &&
dc->pc < next_page_start &&
num_insns < max_insns);
@@ -10097,7 +10098,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
/* At this stage dc->condjmp will only be set when the skipped
instruction was a conditional branch or trap, and the PC has
already been written. */
- if (unlikely(env->singlestep_enabled)) {
+ if (unlikely(cs->singlestep_enabled)) {
/* Make sure the pc is updated, and raise a debug exception. */
if (dc->condjmp) {
gen_set_condexec(dc);
diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h
index af7d14de4b..d7baf0746a 100644
--- a/target-cris/cpu-qom.h
+++ b/target-cris/cpu-qom.h
@@ -79,4 +79,6 @@ void crisv10_cpu_do_interrupt(CPUState *cpu);
void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+
#endif
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 2abb57fc23..ba095e75a5 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -26,6 +26,13 @@
#include "mmu.h"
+static void cris_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ CRISCPU *cpu = CRIS_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
/* CPUClass::reset() */
static void cris_cpu_reset(CPUState *s)
{
@@ -247,6 +254,10 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = cris_cpu_class_by_name;
cc->do_interrupt = cris_cpu_do_interrupt;
cc->dump_state = cris_cpu_dump_state;
+ cc->set_pc = cris_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = cris_cpu_get_phys_page_debug;
+#endif
}
static const TypeInfo cris_cpu_type_info = {
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index c12a8caea1..4b9fc4cb45 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -279,8 +279,4 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUCRISState *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
-}
#endif
diff --git a/target-cris/helper.c b/target-cris/helper.c
index aba7537265..d274b388b8 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -255,16 +255,17 @@ void cris_cpu_do_interrupt(CPUState *cs)
env->pregs[PR_ERP]);
}
-hwaddr cpu_get_phys_page_debug(CPUCRISState * env, target_ulong addr)
+hwaddr cris_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ CRISCPU *cpu = CRIS_CPU(cs);
uint32_t phy = addr;
struct cris_mmu_result res;
int miss;
- miss = cris_mmu_translate(&res, env, addr, 0, 0, 1);
+ miss = cris_mmu_translate(&res, &cpu->env, addr, 0, 0, 1);
/* If D TLB misses, try I TLB. */
if (miss) {
- miss = cris_mmu_translate(&res, env, addr, 2, 0, 1);
+ miss = cris_mmu_translate(&res, &cpu->env, addr, 2, 0, 1);
}
if (!miss) {
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 1de9743953..2a4beeb869 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3165,6 +3165,7 @@ static inline void
gen_intermediate_code_internal(CRISCPU *cpu, TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUCRISState *env = &cpu->env;
uint16_t *gen_opc_end;
uint32_t pc_start;
@@ -3197,7 +3198,7 @@ gen_intermediate_code_internal(CRISCPU *cpu, TranslationBlock *tb,
dc->is_jmp = DISAS_NEXT;
dc->ppc = pc_start;
dc->pc = pc_start;
- dc->singlestep_enabled = env->singlestep_enabled;
+ dc->singlestep_enabled = cs->singlestep_enabled;
dc->flags_uptodate = 1;
dc->flagx_known = 1;
dc->flags_x = tb->flags & X_FLAG;
@@ -3337,7 +3338,7 @@ gen_intermediate_code_internal(CRISCPU *cpu, TranslationBlock *tb,
/* If we are rexecuting a branch due to exceptions on
delay slots dont break. */
- if (!(tb->pc & 1) && env->singlestep_enabled) {
+ if (!(tb->pc & 1) && cs->singlestep_enabled) {
break;
}
} while (!dc->is_jmp && !dc->cpustate_changed
@@ -3370,7 +3371,7 @@ gen_intermediate_code_internal(CRISCPU *cpu, TranslationBlock *tb,
cris_evaluate_flags(dc);
- if (unlikely(env->singlestep_enabled)) {
+ if (unlikely(cs->singlestep_enabled)) {
if (dc->is_jmp == DISAS_NEXT) {
tcg_gen_movi_tl(env_pc, npc);
}
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 7e55e5fd2e..d928562c53 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -104,4 +104,6 @@ void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+
#endif
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index e3f75a81a7..cd350cb8e4 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2506,6 +2506,20 @@ static bool x86_cpu_get_paging_enabled(const CPUState *cs)
return cpu->env.cr[0] & CR0_PG_MASK;
}
+static void x86_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ X86CPU *cpu = X86_CPU(cs);
+
+ cpu->env.eip = value;
+}
+
+static void x86_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+ X86CPU *cpu = X86_CPU(cs);
+
+ cpu->env.eip = tb->pc - tb->cs_base;
+}
+
static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
{
X86CPUClass *xcc = X86_CPU_CLASS(oc);
@@ -2522,16 +2536,19 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = x86_cpu_do_interrupt;
cc->dump_state = x86_cpu_dump_state;
+ cc->set_pc = x86_cpu_set_pc;
+ cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
cc->get_arch_id = x86_cpu_get_arch_id;
cc->get_paging_enabled = x86_cpu_get_paging_enabled;
#ifndef CONFIG_USER_ONLY
cc->get_memory_mapping = x86_cpu_get_memory_mapping;
+ cc->get_phys_page_debug = x86_cpu_get_phys_page_debug;
cc->write_elf64_note = x86_cpu_write_elf64_note;
cc->write_elf64_qemunote = x86_cpu_write_elf64_qemunote;
cc->write_elf32_note = x86_cpu_write_elf32_note;
cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
+ cc->vmsd = &vmstate_x86_cpu;
#endif
- cpu_class_set_vmsd(cc, &vmstate_x86_cpu);
}
static const TypeInfo x86_cpu_type_info = {
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 2d005b3ce9..cedefdc423 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -1148,11 +1148,6 @@ static inline bool cpu_has_work(CPUState *cs)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUX86State *env, TranslationBlock *tb)
-{
- env->eip = tb->pc - tb->cs_base;
-}
-
static inline void cpu_get_tb_cpu_state(CPUX86State *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
diff --git a/target-i386/helper.c b/target-i386/helper.c
index d6f43d7a21..bf3e2ac73d 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -363,7 +363,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, "Code=");
for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
- if (cpu_memory_rw_debug(env, base - offs + i, &code, 1, 0) == 0) {
+ if (cpu_memory_rw_debug(cs, base - offs + i, &code, 1, 0) == 0) {
snprintf(codestr, sizeof(codestr), "%02x", code);
} else {
snprintf(codestr, sizeof(codestr), "??");
@@ -884,8 +884,10 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
return 1;
}
-hwaddr cpu_get_phys_page_debug(CPUX86State *env, target_ulong addr)
+hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
target_ulong pde_addr, pte_addr;
uint64_t pte;
hwaddr paddr;
@@ -1258,6 +1260,8 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
target_ulong *base, unsigned int *limit,
unsigned int *flags)
{
+ X86CPU *cpu = x86_env_get_cpu(env);
+ CPUState *cs = CPU(cpu);
SegmentCache *dt;
target_ulong ptr;
uint32_t e1, e2;
@@ -1270,8 +1274,8 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
index = selector & ~7;
ptr = dt->base + index;
if ((index + 7) > dt->limit
- || cpu_memory_rw_debug(env, ptr, (uint8_t *)&e1, sizeof(e1), 0) != 0
- || cpu_memory_rw_debug(env, ptr+4, (uint8_t *)&e2, sizeof(e2), 0) != 0)
+ || cpu_memory_rw_debug(cs, ptr, (uint8_t *)&e1, sizeof(e1), 0) != 0
+ || cpu_memory_rw_debug(cs, ptr+4, (uint8_t *)&e2, sizeof(e2), 0) != 0)
return 0;
*base = ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 8315489989..3c9d10a762 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1594,6 +1594,7 @@ static int kvm_get_vcpu_events(X86CPU *cpu)
static int kvm_guest_debug_workarounds(X86CPU *cpu)
{
+ CPUState *cs = CPU(cpu);
CPUX86State *env = &cpu->env;
int ret = 0;
unsigned long reinject_trap = 0;
@@ -1616,7 +1617,7 @@ static int kvm_guest_debug_workarounds(X86CPU *cpu)
* reinject them via SET_GUEST_DEBUG.
*/
if (reinject_trap ||
- (!kvm_has_robust_singlestep() && env->singlestep_enabled)) {
+ (!kvm_has_robust_singlestep() && cs->singlestep_enabled)) {
ret = kvm_update_guest_debug(env, reinject_trap);
}
return ret;
@@ -1931,25 +1932,23 @@ static int kvm_handle_tpr_access(X86CPU *cpu)
return 1;
}
-int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp)
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
{
- CPUX86State *env = &X86_CPU(cpu)->env;
static const uint8_t int3 = 0xcc;
- if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0) ||
- cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&int3, 1, 1)) {
+ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0) ||
+ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&int3, 1, 1)) {
return -EINVAL;
}
return 0;
}
-int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp)
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
{
- CPUX86State *env = &X86_CPU(cpu)->env;
uint8_t int3;
- if (cpu_memory_rw_debug(env, bp->pc, &int3, 1, 0) || int3 != 0xcc ||
- cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
+ if (cpu_memory_rw_debug(cs, bp->pc, &int3, 1, 0) || int3 != 0xcc ||
+ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
return -EINVAL;
}
return 0;
@@ -2042,13 +2041,14 @@ static CPUWatchpoint hw_watchpoint;
static int kvm_handle_debug(X86CPU *cpu,
struct kvm_debug_exit_arch *arch_info)
{
+ CPUState *cs = CPU(cpu);
CPUX86State *env = &cpu->env;
int ret = 0;
int n;
if (arch_info->exception == 1) {
if (arch_info->dr6 & (1 << 14)) {
- if (env->singlestep_enabled) {
+ if (cs->singlestep_enabled) {
ret = EXCP_DEBUG;
}
} else {
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 3659db9e94..f9ec581faa 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -252,6 +252,24 @@ static void cpu_pre_save(void *opaque)
}
env->fpregs_format_vmstate = 0;
+
+ /*
+ * Real mode guest segments register DPL should be zero.
+ * Older KVM version were setting it wrongly.
+ * Fixing it will allow live migration to host with unrestricted guest
+ * support (otherwise the migration will fail with invalid guest state
+ * error).
+ */
+ if (!(env->cr[0] & CR0_PE_MASK) &&
+ (env->segs[R_CS].flags >> DESC_DPL_SHIFT & 3) != 0) {
+ env->segs[R_CS].flags &= ~(env->segs[R_CS].flags & DESC_DPL_MASK);
+ env->segs[R_DS].flags &= ~(env->segs[R_DS].flags & DESC_DPL_MASK);
+ env->segs[R_ES].flags &= ~(env->segs[R_ES].flags & DESC_DPL_MASK);
+ env->segs[R_FS].flags &= ~(env->segs[R_FS].flags & DESC_DPL_MASK);
+ env->segs[R_GS].flags &= ~(env->segs[R_GS].flags & DESC_DPL_MASK);
+ env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK);
+ }
+
}
static int cpu_post_load(void *opaque, int version_id)
@@ -260,6 +278,24 @@ static int cpu_post_load(void *opaque, int version_id)
CPUX86State *env = &cpu->env;
int i;
+ /*
+ * Real mode guest segments register DPL should be zero.
+ * Older KVM version were setting it wrongly.
+ * Fixing it will allow live migration from such host that don't have
+ * restricted guest support to a host with unrestricted guest support
+ * (otherwise the migration will fail with invalid guest state
+ * error).
+ */
+ if (!(env->cr[0] & CR0_PE_MASK) &&
+ (env->segs[R_CS].flags >> DESC_DPL_SHIFT & 3) != 0) {
+ env->segs[R_CS].flags &= ~(env->segs[R_CS].flags & DESC_DPL_MASK);
+ env->segs[R_DS].flags &= ~(env->segs[R_DS].flags & DESC_DPL_MASK);
+ env->segs[R_ES].flags &= ~(env->segs[R_ES].flags & DESC_DPL_MASK);
+ env->segs[R_FS].flags &= ~(env->segs[R_FS].flags & DESC_DPL_MASK);
+ env->segs[R_GS].flags &= ~(env->segs[R_GS].flags & DESC_DPL_MASK);
+ env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK);
+ }
+
/* XXX: restore FPU round state */
env->fpstt = (env->fpus_vmstate >> 11) & 7;
env->fpus = env->fpus_vmstate & ~0x3800;
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 6550c27798..065a9d320e 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -8255,6 +8255,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUX86State *env = &cpu->env;
DisasContext dc1, *dc = &dc1;
target_ulong pc_ptr;
@@ -8281,7 +8282,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
dc->iopl = (flags >> IOPL_SHIFT) & 3;
dc->tf = (flags >> TF_SHIFT) & 1;
- dc->singlestep_enabled = env->singlestep_enabled;
+ dc->singlestep_enabled = cs->singlestep_enabled;
dc->cc_op = CC_OP_DYNAMIC;
dc->cc_op_dirty = false;
dc->cs_base = cs_base;
@@ -8302,7 +8303,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
#endif
dc->flags = flags;
- dc->jmp_opt = !(dc->tf || env->singlestep_enabled ||
+ dc->jmp_opt = !(dc->tf || cs->singlestep_enabled ||
(flags & HF_INHIBIT_IRQ_MASK)
#ifndef CONFIG_SOFTMMU
|| (flags & HF_SOFTMMU_MASK)
diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h
index e3bb619dc3..9e2732919d 100644
--- a/target-lm32/cpu-qom.h
+++ b/target-lm32/cpu-qom.h
@@ -78,5 +78,6 @@ extern const struct VMStateDescription vmstate_lm32_cpu;
void lm32_cpu_do_interrupt(CPUState *cpu);
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index 04327acc05..ce55e4807d 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -22,6 +22,13 @@
#include "qemu-common.h"
+static void lm32_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ LM32CPU *cpu = LM32_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
/* CPUClass::reset() */
static void lm32_cpu_reset(CPUState *s)
{
@@ -79,7 +86,11 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = lm32_cpu_do_interrupt;
cc->dump_state = lm32_cpu_dump_state;
- cpu_class_set_vmsd(cc, &vmstate_lm32_cpu);
+ cc->set_pc = lm32_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
+ cc->vmsd = &vmstate_lm32_cpu;
+#endif
}
static const TypeInfo lm32_cpu_type_info = {
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index 856bdc745c..dbfe043551 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -232,9 +232,4 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPULM32State *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
-}
-
#endif
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 615b44e5be..15bc61554d 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -37,10 +37,12 @@ int cpu_lm32_handle_mmu_fault(CPULM32State *env, target_ulong address, int rw,
return 0;
}
-hwaddr cpu_get_phys_page_debug(CPULM32State *env, target_ulong addr)
+hwaddr lm32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ LM32CPU *cpu = LM32_CPU(cs);
+
addr &= TARGET_PAGE_MASK;
- if (env->flags & LM32_FLAG_IGNORE_MSB) {
+ if (cpu->env.flags & LM32_FLAG_IGNORE_MSB) {
return addr & 0x7fffffff;
} else {
return addr;
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index ed12f50740..1247287050 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -1015,6 +1015,7 @@ static inline
void gen_intermediate_code_internal(LM32CPU *cpu,
TranslationBlock *tb, bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPULM32State *env = &cpu->env;
struct DisasContext ctx, *dc = &ctx;
uint16_t *gen_opc_end;
@@ -1032,7 +1033,7 @@ void gen_intermediate_code_internal(LM32CPU *cpu,
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
- dc->singlestep_enabled = env->singlestep_enabled;
+ dc->singlestep_enabled = cs->singlestep_enabled;
dc->nr_nops = 0;
if (pc_start & 3) {
@@ -1077,7 +1078,7 @@ void gen_intermediate_code_internal(LM32CPU *cpu,
} while (!dc->is_jmp
&& tcg_ctx.gen_opc_ptr < gen_opc_end
- && !env->singlestep_enabled
+ && !cs->singlestep_enabled
&& !singlestep
&& (dc->pc < next_page_start)
&& num_insns < max_insns);
@@ -1086,7 +1087,7 @@ void gen_intermediate_code_internal(LM32CPU *cpu,
gen_io_end();
}
- if (unlikely(env->singlestep_enabled)) {
+ if (unlikely(cs->singlestep_enabled)) {
if (dc->is_jmp == DISAS_NEXT) {
tcg_gen_movi_tl(cpu_pc, dc->pc);
}
diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h
index 858bf30088..7115707e91 100644
--- a/target-m68k/cpu-qom.h
+++ b/target-m68k/cpu-qom.h
@@ -73,5 +73,6 @@ static inline M68kCPU *m68k_env_get_cpu(CPUM68KState *env)
void m68k_cpu_do_interrupt(CPUState *cpu);
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c
index 1b6ef664f5..988f476257 100644
--- a/target-m68k/cpu.c
+++ b/target-m68k/cpu.c
@@ -23,6 +23,13 @@
#include "migration/vmstate.h"
+static void m68k_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ M68kCPU *cpu = M68K_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
static void m68k_set_feature(CPUM68KState *env, int feature)
{
env->features |= (1u << feature);
@@ -182,6 +189,10 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
cc->class_by_name = m68k_cpu_class_by_name;
cc->do_interrupt = m68k_cpu_do_interrupt;
cc->dump_state = m68k_cpu_dump_state;
+ cc->set_pc = m68k_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
+#endif
dc->vmsd = &vmstate_m68k_cpu;
}
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 9fdf89ef91..cfd6846347 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -260,9 +260,4 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUM68KState *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
-}
-
#endif
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 54fa419ace..00a7a08e83 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -121,10 +121,11 @@ M68kCPU *cpu_m68k_init(const char *cpu_model)
void m68k_cpu_init_gdb(M68kCPU *cpu)
{
+ CPUState *cs = CPU(cpu);
CPUM68KState *env = &cpu->env;
if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
- gdb_register_coprocessor(env, fpu_gdb_get_reg, fpu_gdb_set_reg,
+ gdb_register_coprocessor(cs, fpu_gdb_get_reg, fpu_gdb_set_reg,
11, "cf-fp.xml", 18);
}
/* TODO: Add [E]MAC registers. */
@@ -290,7 +291,7 @@ int cpu_m68k_handle_mmu_fault (CPUM68KState *env, target_ulong address, int rw,
/* MMU */
/* TODO: This will need fixing once the MMU is implemented. */
-hwaddr cpu_get_phys_page_debug(CPUM68KState *env, target_ulong addr)
+hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
return addr;
}
diff --git a/target-m68k/m68k-semi.c b/target-m68k/m68k-semi.c
index 239fadbad5..94c4983813 100644
--- a/target-m68k/m68k-semi.c
+++ b/target-m68k/m68k-semi.c
@@ -161,8 +161,11 @@ static void m68k_semi_return_u64(CPUM68KState *env, uint64_t ret, uint32_t err)
static int m68k_semi_is_fseek;
-static void m68k_semi_cb(CPUM68KState *env, target_ulong ret, target_ulong err)
+static void m68k_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
{
+ M68kCPU *cpu = M68K_CPU(cs);
+ CPUM68KState *env = &cpu->env;
+
if (m68k_semi_is_fseek) {
/* FIXME: We've already lost the high bits of the fseek
return value. */
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 2d73af50c3..d562eebef3 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2974,6 +2974,7 @@ static inline void
gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUM68KState *env = &cpu->env;
DisasContext dc1, *dc = &dc1;
uint16_t *gen_opc_end;
@@ -2995,7 +2996,7 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
dc->cc_op = CC_OP_DYNAMIC;
- dc->singlestep_enabled = env->singlestep_enabled;
+ dc->singlestep_enabled = cs->singlestep_enabled;
dc->fpcr = env->fpcr;
dc->user = (env->sr & SR_S) == 0;
dc->is_mem = 0;
@@ -3038,14 +3039,14 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
disas_m68k_insn(env, dc);
num_insns++;
} while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
- !env->singlestep_enabled &&
+ !cs->singlestep_enabled &&
!singlestep &&
(pc_offset) < (TARGET_PAGE_SIZE - 32) &&
num_insns < max_insns);
if (tb->cflags & CF_LAST_IO)
gen_io_end();
- if (unlikely(env->singlestep_enabled)) {
+ if (unlikely(cs->singlestep_enabled)) {
/* Make sure the pc is updated, and raise a debug exception. */
if (!dc->is_jmp) {
gen_flush_cc_op(dc);
diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h
index ec2b989a23..1318a36676 100644
--- a/target-microblaze/cpu-qom.h
+++ b/target-microblaze/cpu-qom.h
@@ -74,5 +74,6 @@ static inline MicroBlazeCPU *mb_env_get_cpu(CPUMBState *env)
void mb_cpu_do_interrupt(CPUState *cs);
void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index dce1c7ea67..9f10c8c778 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -26,6 +26,13 @@
#include "migration/vmstate.h"
+static void mb_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+
+ cpu->env.sregs[SR_PC] = value;
+}
+
/* CPUClass::reset() */
static void mb_cpu_reset(CPUState *s)
{
@@ -133,7 +140,11 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = mb_cpu_do_interrupt;
cc->dump_state = mb_cpu_dump_state;
- cpu_class_set_do_unassigned_access(cc, mb_cpu_unassigned_access);
+ cc->set_pc = mb_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->do_unassigned_access = mb_cpu_unassigned_access;
+ cc->get_phys_page_debug = mb_cpu_get_phys_page_debug;
+#endif
dc->vmsd = &vmstate_mb_cpu;
dc->props = mb_properties;
}
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 6c35475fd6..7508cf5a06 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -365,9 +365,4 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUMBState *env, TranslationBlock *tb)
-{
- env->sregs[SR_PC] = tb->pc;
-}
-
#endif
diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c
index c6c96d4488..4fa9ce9cb5 100644
--- a/target-microblaze/helper.c
+++ b/target-microblaze/helper.c
@@ -265,8 +265,10 @@ void mb_cpu_do_interrupt(CPUState *cs)
}
}
-hwaddr cpu_get_phys_page_debug(CPUMBState * env, target_ulong addr)
+hwaddr mb_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+ CPUMBState *env = &cpu->env;
target_ulong vaddr, paddr = 0;
struct microblaze_mmu_lookup lu;
unsigned int hit;
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index eba255b7c6..cd4357703f 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1741,6 +1741,7 @@ static inline void
gen_intermediate_code_internal(MicroBlazeCPU *cpu, TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUMBState *env = &cpu->env;
uint16_t *gen_opc_end;
uint32_t pc_start;
@@ -1766,7 +1767,7 @@ gen_intermediate_code_internal(MicroBlazeCPU *cpu, TranslationBlock *tb,
dc->jmp = JMP_INDIRECT;
}
dc->pc = pc_start;
- dc->singlestep_enabled = env->singlestep_enabled;
+ dc->singlestep_enabled = cs->singlestep_enabled;
dc->cpustate_changed = 0;
dc->abort_at_next_insn = 0;
dc->nr_nops = 0;
@@ -1859,8 +1860,9 @@ gen_intermediate_code_internal(MicroBlazeCPU *cpu, TranslationBlock *tb,
break;
}
}
- if (env->singlestep_enabled)
+ if (cs->singlestep_enabled) {
break;
+ }
} while (!dc->is_jmp && !dc->cpustate_changed
&& tcg_ctx.gen_opc_ptr < gen_opc_end
&& !singlestep
@@ -1887,7 +1889,7 @@ gen_intermediate_code_internal(MicroBlazeCPU *cpu, TranslationBlock *tb,
}
t_sync_flags(dc);
- if (unlikely(env->singlestep_enabled)) {
+ if (unlikely(cs->singlestep_enabled)) {
TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
if (dc->is_jmp != DISAS_JUMP) {
diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h
index 654744a45b..7c8e616392 100644
--- a/target-mips/cpu-qom.h
+++ b/target-mips/cpu-qom.h
@@ -77,5 +77,6 @@ static inline MIPSCPU *mips_env_get_cpu(CPUMIPSState *env)
void mips_cpu_do_interrupt(CPUState *cpu);
void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index 60a3faf2f8..4834c86d02 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -22,6 +22,29 @@
#include "qemu-common.h"
+static void mips_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ env->active_tc.PC = value & ~(target_ulong)1;
+ if (value & 1) {
+ env->hflags |= MIPS_HFLAG_M16;
+ } else {
+ env->hflags &= ~(MIPS_HFLAG_M16);
+ }
+}
+
+static void mips_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ env->active_tc.PC = tb->pc;
+ env->hflags &= ~MIPS_HFLAG_BMASK;
+ env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
+}
+
/* CPUClass::reset() */
static void mips_cpu_reset(CPUState *s)
{
@@ -75,7 +98,12 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
cc->do_interrupt = mips_cpu_do_interrupt;
cc->dump_state = mips_cpu_dump_state;
- cpu_class_set_do_unassigned_access(cc, mips_cpu_unassigned_access);
+ cc->set_pc = mips_cpu_set_pc;
+ cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
+#ifndef CONFIG_USER_ONLY
+ cc->do_unassigned_access = mips_cpu_unassigned_access;
+ cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
+#endif
}
static const TypeInfo mips_cpu_type_info = {
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 7ffd2e36bd..a29c82faf1 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -732,13 +732,6 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUMIPSState *env, TranslationBlock *tb)
-{
- env->active_tc.PC = tb->pc;
- env->hflags &= ~MIPS_HFLAG_BMASK;
- env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
-}
-
static inline void compute_hflags(CPUMIPSState *env)
{
env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 6983b92a11..6feef7bcd6 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -254,13 +254,16 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
}
#if !defined(CONFIG_USER_ONLY)
-hwaddr cpu_get_phys_page_debug(CPUMIPSState *env, target_ulong addr)
+hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ MIPSCPU *cpu = MIPS_CPU(cs);
hwaddr phys_addr;
int prot;
- if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
+ if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0,
+ ACCESS_INT) != 0) {
return -1;
+ }
return phys_addr;
}
#endif
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 8246c200a1..877f8dfe88 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -15543,6 +15543,7 @@ static inline void
gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUMIPSState *env = &cpu->env;
DisasContext ctx;
target_ulong pc_start;
@@ -15561,7 +15562,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
ctx.pc = pc_start;
ctx.saved_pc = -1;
- ctx.singlestep_enabled = env->singlestep_enabled;
+ ctx.singlestep_enabled = cs->singlestep_enabled;
ctx.insn_flags = env->insn_flags;
ctx.tb = tb;
ctx.bstate = BS_NONE;
@@ -15637,8 +15638,9 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
This is what GDB expects and is consistent with what the
hardware does (e.g. if a delay slot instruction faults, the
reported PC is the PC of the branch). */
- if (env->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0)
+ if (cs->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) {
break;
+ }
if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
break;
@@ -15653,9 +15655,10 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
if (singlestep)
break;
}
- if (tb->cflags & CF_LAST_IO)
+ if (tb->cflags & CF_LAST_IO) {
gen_io_end();
- if (env->singlestep_enabled && ctx.bstate != BS_BRANCH) {
+ }
+ if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) {
save_cpu_state(&ctx, ctx.bstate == BS_NONE);
gen_helper_0e0i(raise_exception, EXCP_DEBUG);
} else {
diff --git a/target-moxie/cpu.c b/target-moxie/cpu.c
index 92ca5946bf..6550be5b35 100644
--- a/target-moxie/cpu.c
+++ b/target-moxie/cpu.c
@@ -22,6 +22,13 @@
#include "migration/vmstate.h"
#include "machine.h"
+static void moxie_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ MoxieCPU *cpu = MOXIE_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
static void moxie_cpu_reset(CPUState *s)
{
MoxieCPU *cpu = MOXIE_CPU(s);
@@ -93,7 +100,11 @@ static void moxie_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = moxie_cpu_do_interrupt;
cc->dump_state = moxie_cpu_dump_state;
- cpu_class_set_vmsd(cc, &vmstate_moxie_cpu);
+ cc->set_pc = moxie_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug;
+ cc->vmsd = &vmstate_moxie_cpu;
+#endif
}
static void moxielite_initfn(Object *obj)
diff --git a/target-moxie/cpu.h b/target-moxie/cpu.h
index 72d02c20c1..5ce14b5fd3 100644
--- a/target-moxie/cpu.h
+++ b/target-moxie/cpu.h
@@ -118,6 +118,7 @@ int cpu_moxie_exec(CPUMoxieState *s);
void moxie_cpu_do_interrupt(CPUState *cs);
void moxie_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
+hwaddr moxie_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void moxie_translate_init(void);
int cpu_moxie_signal_handler(int host_signum, void *pinfo,
void *puc);
@@ -143,11 +144,6 @@ static inline int cpu_mmu_index(CPUMoxieState *env)
#include "exec/cpu-all.h"
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUMoxieState *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
-}
-
static inline void cpu_get_tb_cpu_state(CPUMoxieState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
diff --git a/target-moxie/helper.c b/target-moxie/helper.c
index ea0788fcea..b12e4ffcaf 100644
--- a/target-moxie/helper.c
+++ b/target-moxie/helper.c
@@ -118,11 +118,6 @@ int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
return 1;
}
-hwaddr cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
- return addr;
-}
-
#else /* !CONFIG_USER_ONLY */
int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
@@ -162,12 +157,14 @@ void moxie_cpu_do_interrupt(CPUState *cs)
}
}
-hwaddr cpu_get_phys_page_debug(CPUMoxieState *env, target_ulong addr)
+hwaddr moxie_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ MoxieCPU *cpu = MOXIE_CPU(cs);
uint32_t phy = addr;
MoxieMMUResult res;
int miss;
- miss = moxie_mmu_translate(&res, env, addr, 0, 0);
+
+ miss = moxie_mmu_translate(&res, &cpu->env, addr, 0, 0);
if (!miss) {
phy = res.phy;
}
diff --git a/target-moxie/translate.c b/target-moxie/translate.c
index 664d359438..8cc0bb7bfb 100644
--- a/target-moxie/translate.c
+++ b/target-moxie/translate.c
@@ -824,6 +824,7 @@ static inline void
gen_intermediate_code_internal(MoxieCPU *cpu, TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
DisasContext ctx;
target_ulong pc_start;
uint16_t *gen_opc_end;
@@ -871,7 +872,7 @@ gen_intermediate_code_internal(MoxieCPU *cpu, TranslationBlock *tb,
ctx.pc += decode_opc(cpu, &ctx);
num_insns++;
- if (env->singlestep_enabled) {
+ if (cs->singlestep_enabled) {
break;
}
@@ -880,7 +881,7 @@ gen_intermediate_code_internal(MoxieCPU *cpu, TranslationBlock *tb,
}
} while (ctx.bstate == BS_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end);
- if (env->singlestep_enabled) {
+ if (cs->singlestep_enabled) {
tcg_gen_movi_tl(cpu_pc, ctx.pc);
gen_helper_debug(cpu_env);
} else {
diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c
index 6d40f1b85e..7718820ecc 100644
--- a/target-openrisc/cpu.c
+++ b/target-openrisc/cpu.c
@@ -20,6 +20,13 @@
#include "cpu.h"
#include "qemu-common.h"
+static void openrisc_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
/* CPUClass::reset() */
static void openrisc_cpu_reset(CPUState *s)
{
@@ -99,6 +106,7 @@ static ObjectClass *openrisc_cpu_class_by_name(const char *cpu_model)
typename = g_strdup_printf("%s-" TYPE_OPENRISC_CPU, cpu_model);
oc = object_class_by_name(typename);
+ g_free(typename);
if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU) ||
object_class_is_abstract(oc))) {
return NULL;
@@ -146,7 +154,11 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = openrisc_cpu_class_by_name;
cc->do_interrupt = openrisc_cpu_do_interrupt;
cc->dump_state = openrisc_cpu_dump_state;
- device_class_set_vmsd(dc, &vmstate_openrisc_cpu);
+ cc->set_pc = openrisc_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug;
+ dc->vmsd = &vmstate_openrisc_cpu;
+#endif
}
static void cpu_register(const OpenRISCCPUInfo *info)
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 0aff8f20c7..3ddb7674c7 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -349,6 +349,7 @@ int cpu_openrisc_exec(CPUOpenRISCState *s);
void openrisc_cpu_do_interrupt(CPUState *cpu);
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
+hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void openrisc_translate_init(void);
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
target_ulong address,
@@ -428,9 +429,4 @@ static inline target_ulong cpu_get_pc(CPUOpenRISCState *env)
return env->pc;
}
-static inline void cpu_pc_from_tb(CPUOpenRISCState *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
-}
-
#endif /* CPU_OPENRISC_H */
diff --git a/target-openrisc/mmu.c b/target-openrisc/mmu.c
index d354e1f8b2..57f5616e9c 100644
--- a/target-openrisc/mmu.c
+++ b/target-openrisc/mmu.c
@@ -219,12 +219,11 @@ int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
#endif
#ifndef CONFIG_USER_ONLY
-hwaddr cpu_get_phys_page_debug(CPUOpenRISCState *env,
- target_ulong addr)
+hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
hwaddr phys_addr;
int prot;
- OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
return -1;
diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
index f222834fc3..a6050ba6d8 100644
--- a/target-openrisc/translate.c
+++ b/target-openrisc/translate.c
@@ -1662,6 +1662,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu,
TranslationBlock *tb,
int search_pc)
{
+ CPUState *cs = CPU(cpu);
struct DisasContext ctx, *dc = &ctx;
uint16_t *gen_opc_end;
uint32_t pc_start;
@@ -1681,7 +1682,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu,
dc->mem_idx = cpu_mmu_index(&cpu->env);
dc->synced_flags = dc->tb_flags = tb->flags;
dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
- dc->singlestep_enabled = cpu->env.singlestep_enabled;
+ dc->singlestep_enabled = cs->singlestep_enabled;
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("-----------------------------------------\n");
log_cpu_state(CPU(cpu), 0);
@@ -1743,7 +1744,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu,
}
} while (!dc->is_jmp
&& tcg_ctx.gen_opc_ptr < gen_opc_end
- && !cpu->env.singlestep_enabled
+ && !cs->singlestep_enabled
&& !singlestep
&& (dc->pc < next_page_start)
&& num_insns < max_insns);
@@ -1755,7 +1756,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu,
dc->is_jmp = DISAS_UPDATE;
tcg_gen_movi_tl(cpu_pc, dc->pc);
}
- if (unlikely(cpu->env.singlestep_enabled)) {
+ if (unlikely(cs->singlestep_enabled)) {
if (dc->is_jmp == DISAS_NEXT) {
tcg_gen_movi_tl(cpu_pc, dc->pc);
}
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 7132599516..3341c5151d 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -105,5 +105,6 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
+hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 7a7b1bf35a..6f51e1f526 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -2144,11 +2144,6 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUPPCState *env, TranslationBlock *tb)
-{
- env->nip = tb->pc;
-}
-
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
#endif /* !defined (__CPU_PPC_H__) */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 77102c4b65..5dd4e05f78 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1409,8 +1409,10 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-hwaddr cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
+hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
mmu_ctx_t ctx;
switch (env->mmu_model) {
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index eb96272b0e..f07d70d866 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -9730,6 +9730,7 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu,
TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
DisasContext ctx, *ctxp = &ctx;
opc_handler_t **table, *handler;
@@ -9770,8 +9771,9 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu,
ctx.singlestep_enabled = 0;
if ((env->flags & POWERPC_FLAG_BE) && msr_be)
ctx.singlestep_enabled |= CPU_BRANCH_STEP;
- if (unlikely(env->singlestep_enabled))
+ if (unlikely(cs->singlestep_enabled)) {
ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
+ }
#if defined (DO_SINGLE_STEP) && 0
/* Single step trace mode */
msr_se = 1;
@@ -9873,7 +9875,7 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu,
ctx.exception != POWERPC_EXCP_BRANCH)) {
gen_exception(ctxp, POWERPC_EXCP_TRACE);
} else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
- (env->singlestep_enabled) ||
+ (cs->singlestep_enabled) ||
singlestep ||
num_insns >= max_insns)) {
/* if we reach a page boundary or are single stepping, stop
@@ -9887,7 +9889,7 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu,
if (ctx.exception == POWERPC_EXCP_NONE) {
gen_goto_tb(&ctx, 0, ctx.nip);
} else if (ctx.exception != POWERPC_EXCP_BRANCH) {
- if (unlikely(env->singlestep_enabled)) {
+ if (unlikely(cs->singlestep_enabled)) {
gen_debug_exception(ctxp);
}
/* Generate the return instruction */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 79bfcd8df9..0b0844f467 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -7804,8 +7804,8 @@ static int ppc_fixup_cpu(PowerPCCPU *cpu)
static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
{
+ CPUState *cs = CPU(dev);
PowerPCCPU *cpu = POWERPC_CPU(dev);
- CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
Error *local_err = NULL;
#if !defined(CONFIG_USER_ONLY)
@@ -7849,15 +7849,15 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
init_ppc_proc(cpu);
if (pcc->insns_flags & PPC_FLOAT) {
- gdb_register_coprocessor(env, gdb_get_float_reg, gdb_set_float_reg,
+ gdb_register_coprocessor(cs, gdb_get_float_reg, gdb_set_float_reg,
33, "power-fpu.xml", 0);
}
if (pcc->insns_flags & PPC_ALTIVEC) {
- gdb_register_coprocessor(env, gdb_get_avr_reg, gdb_set_avr_reg,
+ gdb_register_coprocessor(cs, gdb_get_avr_reg, gdb_set_avr_reg,
34, "power-altivec.xml", 0);
}
if (pcc->insns_flags & PPC_SPE) {
- gdb_register_coprocessor(env, gdb_get_spe_reg, gdb_set_spe_reg,
+ gdb_register_coprocessor(cs, gdb_get_spe_reg, gdb_set_spe_reg,
34, "power-spe.xml", 0);
}
@@ -7865,6 +7865,7 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
#if defined(PPC_DUMP_CPU)
{
+ CPUPPCState *env = &cpu->env;
const char *mmu_model, *excp_model, *bus_model;
switch (env->mmu_model) {
case POWERPC_MMU_32B:
@@ -8016,10 +8017,10 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
printf(" none\n");
printf(" Time-base/decrementer clock source: %s\n",
env->flags & POWERPC_FLAG_RTC_CLK ? "RTC clock" : "bus clock");
+ dump_ppc_insns(env);
+ dump_ppc_sprs(env);
+ fflush(stdout);
}
- dump_ppc_insns(env);
- dump_ppc_sprs(env);
- fflush(stdout);
#endif
}
@@ -8322,6 +8323,13 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
return cpu_list;
}
+static void ppc_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ cpu->env.nip = value;
+}
+
/* CPUClass::reset() */
static void ppc_cpu_reset(CPUState *s)
{
@@ -8449,6 +8457,10 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = ppc_cpu_do_interrupt;
cc->dump_state = ppc_cpu_dump_state;
cc->dump_statistics = ppc_cpu_dump_statistics;
+ cc->set_pc = ppc_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
+#endif
}
static const TypeInfo ppc_cpu_type_info = {
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index 4c091e3ea0..a4fe8fb5fc 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -74,5 +74,6 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *env)
void s390_cpu_do_interrupt(CPUState *cpu);
void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
+hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 1ef2fc0e86..cb89d1a46b 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -58,6 +58,13 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
}
#endif
+static void s390_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ S390CPU *cpu = S390_CPU(cs);
+
+ cpu->env.psw.addr = value;
+}
+
/* CPUClass::reset() */
static void s390_cpu_reset(CPUState *s)
{
@@ -165,6 +172,10 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = s390_cpu_do_interrupt;
cc->dump_state = s390_cpu_dump_state;
+ cc->set_pc = s390_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
+#endif
dc->vmsd = &vmstate_s390_cpu;
}
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 646268858b..65bef8625f 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -1041,11 +1041,6 @@ static inline bool cpu_has_work(CPUState *cpu)
(env->psw.mask & PSW_MASK_EXT);
}
-static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb)
-{
- env->psw.addr = tb->pc;
-}
-
/* fpu_helper.c */
uint32_t set_cc_nz_f32(float32 v);
uint32_t set_cc_nz_f64(float64 v);
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index b425054be8..61abfd7d9e 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -417,9 +417,10 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr,
return 0;
}
-hwaddr cpu_get_phys_page_debug(CPUS390XState *env,
- target_ulong vaddr)
+hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
target_ulong raddr;
int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
int old_exc = env->exception_index;
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index cba7b87527..1fb76c5264 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -4740,6 +4740,7 @@ static inline void gen_intermediate_code_internal(S390CPU *cpu,
TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUS390XState *env = &cpu->env;
DisasContext dc;
target_ulong pc_start;
@@ -4761,7 +4762,7 @@ static inline void gen_intermediate_code_internal(S390CPU *cpu,
dc.tb = tb;
dc.pc = pc_start;
dc.cc_op = CC_OP_DYNAMIC;
- do_debug = dc.singlestep_enabled = env->singlestep_enabled;
+ do_debug = dc.singlestep_enabled = cs->singlestep_enabled;
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
@@ -4818,7 +4819,7 @@ static inline void gen_intermediate_code_internal(S390CPU *cpu,
|| tcg_ctx.gen_opc_ptr >= gen_opc_end
|| num_insns >= max_insns
|| singlestep
- || env->singlestep_enabled)) {
+ || cs->singlestep_enabled)) {
status = EXIT_PC_STALE;
}
} while (status == NO_EXIT);
diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h
index c229a9a29b..7c9160bab8 100644
--- a/target-sh4/cpu-qom.h
+++ b/target-sh4/cpu-qom.h
@@ -86,5 +86,6 @@ static inline SuperHCPU *sh_env_get_cpu(CPUSH4State *env)
void superh_cpu_do_interrupt(CPUState *cpu);
void superh_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
+hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c
index 03487eb32e..51a77576fb 100644
--- a/target-sh4/cpu.c
+++ b/target-sh4/cpu.c
@@ -24,6 +24,21 @@
#include "migration/vmstate.h"
+static void superh_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ SuperHCPU *cpu = SUPERH_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
+static void superh_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+ SuperHCPU *cpu = SUPERH_CPU(cs);
+
+ cpu->env.pc = tb->pc;
+ cpu->env.flags = tb->flags;
+}
+
/* CPUClass::reset() */
static void superh_cpu_reset(CPUState *s)
{
@@ -269,6 +284,11 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = superh_cpu_class_by_name;
cc->do_interrupt = superh_cpu_do_interrupt;
cc->dump_state = superh_cpu_dump_state;
+ cc->set_pc = superh_cpu_set_pc;
+ cc->synchronize_from_tb = superh_cpu_synchronize_from_tb;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = superh_cpu_get_phys_page_debug;
+#endif
dc->vmsd = &vmstate_sh_cpu;
}
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index c8df18bab1..276d2955c3 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -359,10 +359,4 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUSH4State *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
- env->flags = tb->flags;
-}
-
#endif /* _CPU_SH4_H */
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index cb6a2d28bd..9ac28250e0 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -508,12 +508,13 @@ int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
return 0;
}
-hwaddr cpu_get_phys_page_debug(CPUSH4State * env, target_ulong addr)
+hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ SuperHCPU *cpu = SUPERH_CPU(cs);
target_ulong physical;
int prot;
- get_physical_address(env, &physical, &prot, addr, 0, 0);
+ get_physical_address(&cpu->env, &physical, &prot, addr, 0, 0);
return physical;
}
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 2fbe6685b0..59f3d47023 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -1849,6 +1849,7 @@ static inline void
gen_intermediate_code_internal(SuperHCPU *cpu, TranslationBlock *tb,
bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUSH4State *env = &cpu->env;
DisasContext ctx;
target_ulong pc_start;
@@ -1868,7 +1869,7 @@ gen_intermediate_code_internal(SuperHCPU *cpu, TranslationBlock *tb,
so assume it is a dynamic branch. */
ctx.delayed_pc = -1; /* use delayed pc from env pointer */
ctx.tb = tb;
- ctx.singlestep_enabled = env->singlestep_enabled;
+ ctx.singlestep_enabled = cs->singlestep_enabled;
ctx.features = env->features;
ctx.has_movcal = (ctx.flags & TB_FLAG_PENDING_MOVCA);
@@ -1914,8 +1915,9 @@ gen_intermediate_code_internal(SuperHCPU *cpu, TranslationBlock *tb,
ctx.pc += 2;
if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
break;
- if (env->singlestep_enabled)
+ if (cs->singlestep_enabled) {
break;
+ }
if (num_insns >= max_insns)
break;
if (singlestep)
@@ -1923,7 +1925,7 @@ gen_intermediate_code_internal(SuperHCPU *cpu, TranslationBlock *tb,
}
if (tb->cflags & CF_LAST_IO)
gen_io_end();
- if (env->singlestep_enabled) {
+ if (cs->singlestep_enabled) {
tcg_gen_movi_i32(cpu_pc, ctx.pc);
gen_helper_debug(cpu_env);
} else {
diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h
index 033a5b5219..39d975b5fc 100644
--- a/target-sparc/cpu-qom.h
+++ b/target-sparc/cpu-qom.h
@@ -78,5 +78,6 @@ static inline SPARCCPU *sparc_env_get_cpu(CPUSPARCState *env)
void sparc_cpu_do_interrupt(CPUState *cpu);
void sparc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
+hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 87c3a50c00..d1d03396ef 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -723,6 +723,22 @@ void sparc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, "\n");
}
+static void sparc_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+
+ cpu->env.pc = value;
+ cpu->env.npc = value + 4;
+}
+
+static void sparc_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+
+ cpu->env.pc = tb->pc;
+ cpu->env.npc = tb->cs_base;
+}
+
static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
{
SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(dev);
@@ -766,7 +782,15 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = sparc_cpu_do_interrupt;
cc->dump_state = sparc_cpu_dump_state;
- cpu_class_set_do_unassigned_access(cc, sparc_cpu_unassigned_access);
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+ cc->memory_rw_debug = sparc_cpu_memory_rw_debug;
+#endif
+ cc->set_pc = sparc_cpu_set_pc;
+ cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
+#ifndef CONFIG_USER_ONLY
+ cc->do_unassigned_access = sparc_cpu_unassigned_access;
+ cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
+#endif
}
static const TypeInfo sparc_cpu_type_info = {
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 41b014a0b3..41194ec06b 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -526,9 +526,8 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env);
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
-int target_memory_rw_debug(CPUSPARCState *env, target_ulong addr,
- uint8_t *buf, int len, int is_write);
-#define TARGET_CPU_MEMORY_RW_DEBUG
+int sparc_cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
+ uint8_t *buf, int len, bool is_write);
#endif
@@ -759,10 +758,4 @@ static inline bool cpu_has_work(CPUState *cpu)
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUSPARCState *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
- env->npc = tb->cs_base;
-}
-
#endif
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
index 740cbe8f2c..ef12a0a8d0 100644
--- a/target-sparc/mmu_helper.c
+++ b/target-sparc/mmu_helper.c
@@ -310,6 +310,7 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
{
+ CPUState *cs = CPU(sparc_env_get_cpu(env));
target_ulong va, va1, va2;
unsigned int n, m, o;
hwaddr pde_ptr, pa;
@@ -322,20 +323,20 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
pde = mmu_probe(env, va, 2);
if (pde) {
- pa = cpu_get_phys_page_debug(env, va);
+ pa = cpu_get_phys_page_debug(cs, va);
(*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
" PDE: " TARGET_FMT_lx "\n", va, pa, pde);
for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
pde = mmu_probe(env, va1, 1);
if (pde) {
- pa = cpu_get_phys_page_debug(env, va1);
+ pa = cpu_get_phys_page_debug(cs, va1);
(*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
va1, pa, pde);
for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
pde = mmu_probe(env, va2, 0);
if (pde) {
- pa = cpu_get_phys_page_debug(env, va2);
+ pa = cpu_get_phys_page_debug(cs, va2);
(*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
TARGET_FMT_plx " PTE: "
TARGET_FMT_lx "\n",
@@ -352,9 +353,12 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
* reads (and only reads) in stack frames as if windows were flushed. We assume
* that the sparc ABI is followed.
*/
-int target_memory_rw_debug(CPUSPARCState *env, target_ulong addr,
- uint8_t *buf, int len, int is_write)
+int sparc_cpu_memory_rw_debug(CPUState *cs, vaddr address,
+ uint8_t *buf, int len, bool is_write)
{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+ CPUSPARCState *env = &cpu->env;
+ target_ulong addr = address;
int i;
int len1;
int cwp = env->cwp;
@@ -389,7 +393,7 @@ int target_memory_rw_debug(CPUSPARCState *env, target_ulong addr,
/* Handle access before this window. */
if (addr < fp) {
len1 = fp - addr;
- if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
+ if (cpu_memory_rw_debug(cs, addr, buf, len1, is_write) != 0) {
return -1;
}
addr += len1;
@@ -425,7 +429,7 @@ int target_memory_rw_debug(CPUSPARCState *env, target_ulong addr,
}
}
}
- return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+ return cpu_memory_rw_debug(cs, addr, buf, len, is_write);
}
#else /* !TARGET_SPARC64 */
@@ -833,8 +837,10 @@ hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
}
#endif
-hwaddr cpu_get_phys_page_debug(CPUSPARCState *env, target_ulong addr)
+hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+ CPUSPARCState *env = &cpu->env;
hwaddr phys_addr;
int mmu_idx = cpu_mmu_index(env);
MemoryRegionSection section;
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 5e771e5da7..093e0e2c78 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -5223,6 +5223,7 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu,
TranslationBlock *tb,
bool spc)
{
+ CPUState *cs = CPU(cpu);
CPUSPARCState *env = &cpu->env;
target_ulong pc_start, last_pc;
uint16_t *gen_opc_end;
@@ -5244,7 +5245,7 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu,
dc->def = env->def;
dc->fpu_enabled = tb_fpu_enabled(tb->flags);
dc->address_mask_32bit = tb_am_enabled(tb->flags);
- dc->singlestep = (env->singlestep_enabled || singlestep);
+ dc->singlestep = (cs->singlestep_enabled || singlestep);
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
num_insns = 0;
diff --git a/target-unicore32/cpu-qom.h b/target-unicore32/cpu-qom.h
index 350d48034c..f727760d9e 100644
--- a/target-unicore32/cpu-qom.h
+++ b/target-unicore32/cpu-qom.h
@@ -63,5 +63,6 @@ static inline UniCore32CPU *uc32_env_get_cpu(CPUUniCore32State *env)
void uc32_cpu_do_interrupt(CPUState *cpu);
void uc32_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
+hwaddr uc32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index 6572f0199b..46813e52ae 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -16,6 +16,13 @@
#include "qemu-common.h"
#include "migration/vmstate.h"
+static void uc32_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ UniCore32CPU *cpu = UNICORE32_CPU(cs);
+
+ cpu->env.regs[31] = value;
+}
+
static inline void set_feature(CPUUniCore32State *env, int feature)
{
env->features |= feature;
@@ -131,6 +138,10 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = uc32_cpu_class_by_name;
cc->do_interrupt = uc32_cpu_do_interrupt;
cc->dump_state = uc32_cpu_dump_state;
+ cc->set_pc = uc32_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug;
+#endif
dc->vmsd = &vmstate_uc32_cpu;
}
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index d4be5252f3..967511e3f6 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -146,11 +146,6 @@ static inline int cpu_mmu_index(CPUUniCore32State *env)
#include "cpu-qom.h"
#include "exec/exec-all.h"
-static inline void cpu_pc_from_tb(CPUUniCore32State *env, TranslationBlock *tb)
-{
- env->regs[31] = tb->pc;
-}
-
static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c
index eadaeb11ab..1e13a85d05 100644
--- a/target-unicore32/softmmu.c
+++ b/target-unicore32/softmmu.c
@@ -261,9 +261,10 @@ int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
return ret;
}
-hwaddr cpu_get_phys_page_debug(CPUUniCore32State *env,
- target_ulong addr)
+hwaddr uc32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
- cpu_abort(env, "%s not supported yet\n", __func__);
+ UniCore32CPU *cpu = UNICORE32_CPU(cs);
+
+ cpu_abort(&cpu->env, "%s not supported yet\n", __func__);
return addr;
}
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index d85185df36..68be1c64e0 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -1879,6 +1879,7 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
static inline void gen_intermediate_code_internal(UniCore32CPU *cpu,
TranslationBlock *tb, bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUUniCore32State *env = &cpu->env;
DisasContext dc1, *dc = &dc1;
CPUBreakpoint *bp;
@@ -1900,7 +1901,7 @@ static inline void gen_intermediate_code_internal(UniCore32CPU *cpu,
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
- dc->singlestep_enabled = env->singlestep_enabled;
+ dc->singlestep_enabled = cs->singlestep_enabled;
dc->condjmp = 0;
cpu_F0s = tcg_temp_new_i32();
cpu_F1s = tcg_temp_new_i32();
@@ -1971,7 +1972,7 @@ static inline void gen_intermediate_code_internal(UniCore32CPU *cpu,
* ensures prefetch aborts occur at the right place. */
num_insns++;
} while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
- !env->singlestep_enabled &&
+ !cs->singlestep_enabled &&
!singlestep &&
dc->pc < next_page_start &&
num_insns < max_insns);
@@ -1988,7 +1989,7 @@ static inline void gen_intermediate_code_internal(UniCore32CPU *cpu,
/* At this stage dc->condjmp will only be set when the skipped
instruction was a conditional branch or trap, and the PC has
already been written. */
- if (unlikely(env->singlestep_enabled)) {
+ if (unlikely(cs->singlestep_enabled)) {
/* Make sure the pc is updated, and raise a debug exception. */
if (dc->condjmp) {
if (dc->is_jmp == DISAS_SYSCALL) {
diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h
index 31e7498181..b9896f2647 100644
--- a/target-xtensa/cpu-qom.h
+++ b/target-xtensa/cpu-qom.h
@@ -83,5 +83,6 @@ static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env)
void xtensa_cpu_do_interrupt(CPUState *cpu);
void xtensa_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
+hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index 0488984d4a..d2bcfc69a2 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -33,6 +33,13 @@
#include "migration/vmstate.h"
+static void xtensa_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ XtensaCPU *cpu = XTENSA_CPU(cs);
+
+ cpu->env.pc = value;
+}
+
/* CPUClass::reset() */
static void xtensa_cpu_reset(CPUState *s)
{
@@ -100,6 +107,10 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = xtensa_cpu_do_interrupt;
cc->dump_state = xtensa_cpu_dump_state;
+ cc->set_pc = xtensa_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;
+#endif
dc->vmsd = &vmstate_xtensa_cpu;
}
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 6c9fc35dcc..a8f02f6e4b 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -522,9 +522,4 @@ static inline int cpu_has_work(CPUState *cpu)
return env->pending_irq_level;
}
-static inline void cpu_pc_from_tb(CPUXtensaState *env, TranslationBlock *tb)
-{
- env->pc = tb->pc;
-}
-
#endif
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 6f613c66a6..de6cc3b7c5 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -108,17 +108,18 @@ void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
}
}
-hwaddr cpu_get_phys_page_debug(CPUXtensaState *env, target_ulong addr)
+hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
+ XtensaCPU *cpu = XTENSA_CPU(cs);
uint32_t paddr;
uint32_t page_size;
unsigned access;
- if (xtensa_get_physical_addr(env, false, addr, 0, 0,
+ if (xtensa_get_physical_addr(&cpu->env, false, addr, 0, 0,
&paddr, &page_size, &access) == 0) {
return paddr;
}
- if (xtensa_get_physical_addr(env, false, addr, 2, 0,
+ if (xtensa_get_physical_addr(&cpu->env, false, addr, 2, 0,
&paddr, &page_size, &access) == 0) {
return paddr;
}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index e4cf828630..e692329157 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -2879,6 +2879,7 @@ static inline
void gen_intermediate_code_internal(XtensaCPU *cpu,
TranslationBlock *tb, bool search_pc)
{
+ CPUState *cs = CPU(cpu);
CPUXtensaState *env = &cpu->env;
DisasContext dc;
int insn_count = 0;
@@ -2894,7 +2895,7 @@ void gen_intermediate_code_internal(XtensaCPU *cpu,
}
dc.config = env->config;
- dc.singlestep_enabled = env->singlestep_enabled;
+ dc.singlestep_enabled = cs->singlestep_enabled;
dc.tb = tb;
dc.pc = pc_start;
dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
@@ -2917,7 +2918,7 @@ void gen_intermediate_code_internal(XtensaCPU *cpu,
gen_tb_start();
- if (env->singlestep_enabled && env->exception_taken) {
+ if (cs->singlestep_enabled && env->exception_taken) {
env->exception_taken = 0;
tcg_gen_movi_i32(cpu_pc, dc.pc);
gen_exception(&dc, EXCP_DEBUG);
@@ -2970,7 +2971,7 @@ void gen_intermediate_code_internal(XtensaCPU *cpu,
if (dc.icount) {
tcg_gen_mov_i32(cpu_SR[ICOUNT], dc.next_icount);
}
- if (env->singlestep_enabled) {
+ if (cs->singlestep_enabled) {
tcg_gen_movi_i32(cpu_pc, dc.pc);
gen_exception(&dc, EXCP_DEBUG);
break;
diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c
index 5fe0361c02..424253d1f3 100644
--- a/target-xtensa/xtensa-semi.c
+++ b/target-xtensa/xtensa-semi.c
@@ -152,6 +152,7 @@ static uint32_t errno_h2g(int host_errno)
void HELPER(simcall)(CPUXtensaState *env)
{
+ CPUState *cs = CPU(xtensa_env_get_cpu(env));
uint32_t *regs = env->regs;
switch (regs[2]) {
@@ -169,8 +170,7 @@ void HELPER(simcall)(CPUXtensaState *env)
uint32_t len = regs[5];
while (len > 0) {
- hwaddr paddr =
- cpu_get_phys_page_debug(env, vaddr);
+ hwaddr paddr = cpu_get_phys_page_debug(cs, vaddr);
uint32_t page_left =
TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1));
uint32_t io_sz = page_left < len ? page_left : len;
@@ -204,8 +204,8 @@ void HELPER(simcall)(CPUXtensaState *env)
int i;
for (i = 0; i < ARRAY_SIZE(name); ++i) {
- rc = cpu_memory_rw_debug(
- env, regs[3] + i, (uint8_t *)name + i, 1, 0);
+ rc = cpu_memory_rw_debug(cs, regs[3] + i,
+ (uint8_t *)name + i, 1, 0);
if (rc != 0 || name[i] == 0) {
break;
}
@@ -249,7 +249,7 @@ void HELPER(simcall)(CPUXtensaState *env)
FD_SET(fd, &fdset);
if (target_tv) {
- cpu_memory_rw_debug(env, target_tv,
+ cpu_memory_rw_debug(cs, target_tv,
(uint8_t *)target_tvv, sizeof(target_tvv), 0);
tv.tv_sec = (int32_t)tswap32(target_tvv[0]);
tv.tv_usec = (int32_t)tswap32(target_tvv[1]);
@@ -284,8 +284,8 @@ void HELPER(simcall)(CPUXtensaState *env)
};
argv.argptr[0] = tswap32(regs[3] + offsetof(struct Argv, text));
- cpu_memory_rw_debug(
- env, regs[3], (uint8_t *)&argv, sizeof(argv), 1);
+ cpu_memory_rw_debug(cs,
+ regs[3], (uint8_t *)&argv, sizeof(argv), 1);
}
break;
diff --git a/tests/Makefile b/tests/Makefile
index 279d5f8307..cdbb79e111 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -47,28 +47,41 @@ gcov-files-test-mul64-y = util/host-utils.c
check-unit-y += tests/test-int128$(EXESUF)
# all code tested by test-int128 is inside int128.h
gcov-files-test-int128-y =
+check-unit-y += tests/test-bitops$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
# All QTests for now are POSIX-only, but the dependencies are
# really in libqtest, not in the testcases themselves.
-check-qtest-i386-y = tests/fdc-test$(EXESUF)
+check-qtest-i386-y = tests/endianness-test$(EXESUF)
+check-qtest-i386-y += tests/fdc-test$(EXESUF)
gcov-files-i386-y = hw/fdc.c
check-qtest-i386-y += tests/ide-test$(EXESUF)
check-qtest-i386-y += tests/hd-geo-test$(EXESUF)
gcov-files-i386-y += hw/hd-geometry.c
+check-qtest-i386-y += tests/boot-order-test$(EXESUF)
check-qtest-i386-y += tests/rtc-test$(EXESUF)
check-qtest-i386-y += tests/i440fx-test$(EXESUF)
check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
check-qtest-x86_64-y = $(check-qtest-i386-y)
gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c
gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
+check-qtest-mips-y = tests/endianness-test$(EXESUF)
+check-qtest-mips64-y = tests/endianness-test$(EXESUF)
+check-qtest-mips64el-y = tests/endianness-test$(EXESUF)
+check-qtest-ppc-y = tests/endianness-test$(EXESUF)
+check-qtest-ppc64-y = tests/endianness-test$(EXESUF)
+check-qtest-sh4-y = tests/endianness-test$(EXESUF)
+check-qtest-sh4eb-y = tests/endianness-test$(EXESUF)
+check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
#check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
-#check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)
+#check-qtest-sparc64-y += tests/m48t59-test$(EXESUF)
gcov-files-sparc-y += hw/m48t59.c
gcov-files-sparc64-y += hw/m48t59.c
check-qtest-arm-y = tests/tmp105-test$(EXESUF)
gcov-files-arm-y += hw/tmp105.c
+check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
+check-qtest-ppc64-y += tests/boot-order-test$(EXESUF)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
@@ -122,18 +135,21 @@ tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marsh
tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
+tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a
libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o
libqos-obj-y += tests/libqos/i2c.o
-libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o tests/libqos/fw_cfg-pc.o
+libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
libqos-pc-obj-y += tests/libqos/malloc-pc.o
libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
tests/rtc-test$(EXESUF): tests/rtc-test.o
tests/m48t59-test$(EXESUF): tests/m48t59-test.o
+tests/endianness-test$(EXESUF): tests/endianness-test.o
tests/fdc-test$(EXESUF): tests/fdc-test.o
tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
+tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
@@ -226,3 +242,4 @@ check-block: $(patsubst %,check-%, $(check-block-y))
check: check-unit check-qtest
-include $(wildcard tests/*.d)
+-include $(wildcard tests/libqos/*.d)
diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
new file mode 100644
index 0000000000..4b233d0b24
--- /dev/null
+++ b/tests/boot-order-test.c
@@ -0,0 +1,209 @@
+/*
+ * Boot order test cases.
+ *
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Authors:
+ * Markus Armbruster <armbru@redhat.com>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "libqos/fw_cfg.h"
+#include "libqtest.h"
+
+#define NO_QEMU_PROTOS
+#include "hw/nvram/fw_cfg.h"
+#undef NO_QEMU_PROTOS
+
+typedef struct {
+ const char *args;
+ uint64_t expected_boot;
+ uint64_t expected_reboot;
+} boot_order_test;
+
+static void test_a_boot_order(const char *machine,
+ const char *test_args,
+ uint64_t (*read_boot_order)(void),
+ uint64_t expected_boot,
+ uint64_t expected_reboot)
+{
+ char *args;
+ uint64_t actual;
+
+ args = g_strdup_printf("-nodefaults -display none%s%s %s",
+ machine ? " -M " : "",
+ machine ?: "",
+ test_args);
+ qtest_start(args);
+ actual = read_boot_order();
+ g_assert_cmphex(actual, ==, expected_boot);
+ qmp("{ 'execute': 'system_reset' }");
+ /*
+ * system_reset only requests reset. We get a RESET event after
+ * the actual reset completes. Need to wait for that.
+ */
+ qmp(""); /* HACK: wait for event */
+ actual = read_boot_order();
+ g_assert_cmphex(actual, ==, expected_reboot);
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+static void test_boot_orders(const char *machine,
+ uint64_t (*read_boot_order)(void),
+ const boot_order_test *tests)
+{
+ int i;
+
+ for (i = 0; tests[i].args; i++) {
+ test_a_boot_order(machine, tests[i].args,
+ read_boot_order,
+ tests[i].expected_boot,
+ tests[i].expected_reboot);
+ }
+}
+
+static uint8_t read_mc146818(uint16_t port, uint8_t reg)
+{
+ outb(port, reg);
+ return inb(port + 1);
+}
+
+static uint64_t read_boot_order_pc(void)
+{
+ uint8_t b1 = read_mc146818(0x70, 0x38);
+ uint8_t b2 = read_mc146818(0x70, 0x3d);
+
+ return b1 | (b2 << 8);
+}
+
+static const boot_order_test test_cases_pc[] = {
+ { "",
+ 0x1230, 0x1230 },
+ { "-no-fd-bootchk",
+ 0x1231, 0x1231 },
+ { "-boot c",
+ 0x0200, 0x0200 },
+ { "-boot nda",
+ 0x3410, 0x3410 },
+ { "-boot order=",
+ 0, 0 },
+ { "-boot order= -boot order=c",
+ 0x0200, 0x0200 },
+ { "-boot once=a",
+ 0x0100, 0x1230 },
+ { "-boot once=a -no-fd-bootchk",
+ 0x0101, 0x1231 },
+ { "-boot once=a,order=c",
+ 0x0100, 0x0200 },
+ { "-boot once=d -boot order=nda",
+ 0x0300, 0x3410 },
+ { "-boot once=a -boot once=b -boot once=c",
+ 0x0200, 0x1230 },
+ {}
+};
+
+static void test_pc_boot_order(void)
+{
+ test_boot_orders(NULL, read_boot_order_pc, test_cases_pc);
+}
+
+static uint8_t read_m48t59(uint64_t addr, uint16_t reg)
+{
+ writeb(addr, reg & 0xff);
+ writeb(addr + 1, reg >> 8);
+ return readb(addr + 3);
+}
+
+static uint64_t read_boot_order_prep(void)
+{
+ return read_m48t59(0x80000000 + 0x74, 0x34);
+}
+
+static const boot_order_test test_cases_prep[] = {
+ { "", 'c', 'c' },
+ { "-boot c", 'c', 'c' },
+ { "-boot d", 'd', 'd' },
+ {}
+};
+
+static void test_prep_boot_order(void)
+{
+ test_boot_orders("prep", read_boot_order_prep, test_cases_prep);
+}
+
+static uint64_t read_boot_order_pmac(void)
+{
+ QFWCFG *fw_cfg = mm_fw_cfg_init(0xf0000510);
+
+ return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static const boot_order_test test_cases_fw_cfg[] = {
+ { "", 'c', 'c' },
+ { "-boot c", 'c', 'c' },
+ { "-boot d", 'd', 'd' },
+ { "-boot once=d,order=c", 'd', 'c' },
+ {}
+};
+
+static void test_pmac_oldworld_boot_order(void)
+{
+ test_boot_orders("g3beige", read_boot_order_pmac, test_cases_fw_cfg);
+}
+
+static void test_pmac_newworld_boot_order(void)
+{
+ test_boot_orders("mac99", read_boot_order_pmac, test_cases_fw_cfg);
+}
+
+static uint64_t read_boot_order_sun4m(void)
+{
+ QFWCFG *fw_cfg = mm_fw_cfg_init(0xd00000510ULL);
+
+ return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static void test_sun4m_boot_order(void)
+{
+ test_boot_orders("SS-5", read_boot_order_sun4m, test_cases_fw_cfg);
+}
+
+static uint64_t read_boot_order_sun4u(void)
+{
+ QFWCFG *fw_cfg = io_fw_cfg_init(0x510);
+
+ return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static void test_sun4u_boot_order(void)
+{
+ test_boot_orders("sun4u", read_boot_order_sun4u, test_cases_fw_cfg);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *arch = qtest_get_arch();
+
+ g_test_init(&argc, &argv, NULL);
+
+ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+ qtest_add_func("boot-order/pc", test_pc_boot_order);
+ } else if (strcmp(arch, "ppc") == 0 || strcmp(arch, "ppc64") == 0) {
+ qtest_add_func("boot-order/prep", test_prep_boot_order);
+ qtest_add_func("boot-order/pmac_oldworld",
+ test_pmac_oldworld_boot_order);
+ qtest_add_func("boot-order/pmac_newworld",
+ test_pmac_newworld_boot_order);
+ } else if (strcmp(arch, "sparc") == 0) {
+ qtest_add_func("boot-order/sun4m", test_sun4m_boot_order);
+ } else if (strcmp(arch, "sparc64") == 0) {
+ qtest_add_func("boot-order/sun4u", test_sun4u_boot_order);
+ }
+
+ return g_test_run();
+}
diff --git a/tests/endianness-test.c b/tests/endianness-test.c
new file mode 100644
index 0000000000..feb32a8503
--- /dev/null
+++ b/tests/endianness-test.c
@@ -0,0 +1,316 @@
+/*
+ * QTest testcase for ISA endianness
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "libqtest.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "qemu/bswap.h"
+
+typedef struct TestCase TestCase;
+struct TestCase {
+ const char *arch;
+ const char *machine;
+ uint64_t isa_base;
+ bool bswap;
+ const char *superio;
+};
+
+static const TestCase test_cases[] = {
+ { "i386", "pc", -1 },
+ { "mips", "magnum", 0x90000000, .bswap = true },
+ { "mips", "pica61", 0x90000000, .bswap = true },
+ { "mips", "mips", 0x14000000, .bswap = true },
+ { "mips", "malta", 0x10000000, .bswap = true },
+ { "mips64", "magnum", 0x90000000, .bswap = true },
+ { "mips64", "pica61", 0x90000000, .bswap = true },
+ { "mips64", "mips", 0x14000000, .bswap = true },
+ { "mips64", "malta", 0x10000000, .bswap = true },
+ { "mips64el", "fulong2e", 0x1fd00000 },
+ { "ppc", "g3beige", 0xfe000000, .bswap = true, .superio = "i82378" },
+ { "ppc", "prep", 0x80000000, .bswap = true },
+ { "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" },
+ { "ppc64", "mac99", 0xf2000000, .bswap = true, .superio = "i82378" },
+ { "ppc64", "pseries", 0x10080000000, .bswap = true, .superio = "i82378" },
+ { "sh4", "r2d", 0xfe240000, .superio = "i82378" },
+ { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" },
+ { "sparc64", "sun4u", 0x1fe02000000LL, .bswap = true },
+ { "x86_64", "pc", -1 },
+ {}
+};
+
+static uint8_t isa_inb(const TestCase *test, uint16_t addr)
+{
+ uint8_t value;
+ if (test->isa_base == -1) {
+ value = inb(addr);
+ } else {
+ value = readb(test->isa_base + addr);
+ }
+ return value;
+}
+
+static uint16_t isa_inw(const TestCase *test, uint16_t addr)
+{
+ uint16_t value;
+ if (test->isa_base == -1) {
+ value = inw(addr);
+ } else {
+ value = readw(test->isa_base + addr);
+ }
+ return test->bswap ? bswap16(value) : value;
+}
+
+static uint32_t isa_inl(const TestCase *test, uint16_t addr)
+{
+ uint32_t value;
+ if (test->isa_base == -1) {
+ value = inl(addr);
+ } else {
+ value = readl(test->isa_base + addr);
+ }
+ return test->bswap ? bswap32(value) : value;
+}
+
+static void isa_outb(const TestCase *test, uint16_t addr, uint8_t value)
+{
+ if (test->isa_base == -1) {
+ outb(addr, value);
+ } else {
+ writeb(test->isa_base + addr, value);
+ }
+}
+
+static void isa_outw(const TestCase *test, uint16_t addr, uint16_t value)
+{
+ value = test->bswap ? bswap16(value) : value;
+ if (test->isa_base == -1) {
+ outw(addr, value);
+ } else {
+ writew(test->isa_base + addr, value);
+ }
+}
+
+static void isa_outl(const TestCase *test, uint16_t addr, uint32_t value)
+{
+ value = test->bswap ? bswap32(value) : value;
+ if (test->isa_base == -1) {
+ outl(addr, value);
+ } else {
+ writel(test->isa_base + addr, value);
+ }
+}
+
+
+static void test_endianness(gconstpointer data)
+{
+ const TestCase *test = data;
+ char *args;
+
+ args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev",
+ test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ qtest_start(args);
+ isa_outl(test, 0xe0, 0x87654321);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
+
+ isa_outw(test, 0xe2, 0x8866);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
+
+ isa_outw(test, 0xe0, 0x4422);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
+
+ isa_outb(test, 0xe3, 0x87);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
+
+ isa_outb(test, 0xe2, 0x65);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
+
+ isa_outb(test, 0xe1, 0x43);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
+
+ isa_outb(test, 0xe0, 0x21);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+static void test_endianness_split(gconstpointer data)
+{
+ const TestCase *test = data;
+ char *args;
+
+ args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev",
+ test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ qtest_start(args);
+ isa_outl(test, 0xe8, 0x87654321);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+
+ isa_outw(test, 0xea, 0x8866);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+
+ isa_outw(test, 0xe8, 0x4422);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
+
+ isa_outb(test, 0xeb, 0x87);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766);
+
+ isa_outb(test, 0xea, 0x65);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
+
+ isa_outb(test, 0xe9, 0x43);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322);
+
+ isa_outb(test, 0xe8, 0x21);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+static void test_endianness_combine(gconstpointer data)
+{
+ const TestCase *test = data;
+ char *args;
+
+ args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev",
+ test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ qtest_start(args);
+ isa_outl(test, 0xe0, 0x87654321);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
+
+ isa_outw(test, 0xe2, 0x8866);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
+
+ isa_outw(test, 0xe0, 0x4422);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422);
+
+ isa_outb(test, 0xe3, 0x87);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8766);
+
+ isa_outb(test, 0xe2, 0x65);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422);
+
+ isa_outb(test, 0xe1, 0x43);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4322);
+
+ isa_outb(test, 0xe0, 0x21);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+int main(int argc, char **argv)
+{
+ const char *arch = qtest_get_arch();
+ int ret;
+ int i;
+
+ g_test_init(&argc, &argv, NULL);
+
+ for (i = 0; test_cases[i].arch; i++) {
+ gchar *path;
+ if (strcmp(test_cases[i].arch, arch) != 0) {
+ continue;
+ }
+ path = g_strdup_printf("/%s/endianness/%s",
+ arch, test_cases[i].machine);
+ g_test_add_data_func(path, &test_cases[i], test_endianness);
+
+ path = g_strdup_printf("/%s/endianness/split/%s",
+ arch, test_cases[i].machine);
+ g_test_add_data_func(path, &test_cases[i], test_endianness_split);
+
+ path = g_strdup_printf("/%s/endianness/combine/%s",
+ arch, test_cases[i].machine);
+ g_test_add_data_func(path, &test_cases[i], test_endianness_combine);
+ }
+
+ ret = g_test_run();
+
+ return ret;
+}
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 4b0301da46..fd198dcf8b 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -556,7 +556,7 @@ int main(int argc, char **argv)
ret = g_test_run();
/* Cleanup */
- qtest_quit(global_qtest);
+ qtest_end();
unlink(test_image);
return ret;
diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c
index c284c4d743..b86e49ab09 100644
--- a/tests/fw_cfg-test.c
+++ b/tests/fw_cfg-test.c
@@ -14,7 +14,7 @@
#include "libqtest.h"
#include "hw/nvram/fw_cfg.h"
-#include "libqos/fw_cfg-pc.h"
+#include "libqos/fw_cfg.h"
#include <string.h>
#include <glib.h>
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
index 9a31e8587f..b72042e59d 100644
--- a/tests/hd-geo-test.c
+++ b/tests/hd-geo-test.c
@@ -244,7 +244,7 @@ static void test_ide_none(void)
setup_common(argv, ARRAY_SIZE(argv));
qtest_start(g_strjoinv(" ", argv));
test_cmos();
- qtest_quit(global_qtest);
+ qtest_end();
}
static void test_ide_mbr(bool use_device, MBRcontents mbr)
@@ -262,7 +262,7 @@ static void test_ide_mbr(bool use_device, MBRcontents mbr)
}
qtest_start(g_strjoinv(" ", argv));
test_cmos();
- qtest_quit(global_qtest);
+ qtest_end();
}
/*
@@ -334,7 +334,7 @@ static void test_ide_drive_user(const char *dev, bool trans)
g_free(opts);
qtest_start(g_strjoinv(" ", argv));
test_cmos();
- qtest_quit(global_qtest);
+ qtest_end();
}
/*
@@ -387,7 +387,7 @@ static void test_ide_drive_cd_0(void)
}
qtest_start(g_strjoinv(" ", argv));
test_cmos();
- qtest_quit(global_qtest);
+ qtest_end();
}
int main(int argc, char **argv)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 7e2eb9455a..7307f1d336 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -122,7 +122,7 @@ static void ide_test_start(const char *cmdline_fmt, ...)
static void ide_test_quit(void)
{
- qtest_quit(global_qtest);
+ qtest_end();
}
static QPCIDevice *get_pci_device(uint16_t *bmdma_base)
diff --git a/tests/libqos/fw_cfg-pc.c b/tests/libqos/fw_cfg-pc.c
deleted file mode 100644
index 613604db77..0000000000
--- a/tests/libqos/fw_cfg-pc.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * libqos fw_cfg support for PC
- *
- * Copyright IBM, Corp. 2012-2013
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "libqos/fw_cfg-pc.h"
-#include "libqtest.h"
-#include <glib.h>
-
-static void pc_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
-{
- outw(0x510, key);
-}
-
-static void pc_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
-{
- uint8_t *ptr = data;
- int i;
-
- for (i = 0; i < len; i++) {
- ptr[i] = inb(0x511);
- }
-}
-
-QFWCFG *pc_fw_cfg_init(void)
-{
- QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
-
- fw_cfg->select = pc_fw_cfg_select;
- fw_cfg->read = pc_fw_cfg_read;
-
- return fw_cfg;
-}
diff --git a/tests/libqos/fw_cfg-pc.h b/tests/libqos/fw_cfg-pc.h
deleted file mode 100644
index 444bd7975a..0000000000
--- a/tests/libqos/fw_cfg-pc.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * libqos fw_cfg support for PC
- *
- * Copyright IBM, Corp. 2012-2013
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * 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 LIBQOS_FW_CFG_PC_H
-#define LIBQOS_FW_CFG_PC_H
-
-#include "libqos/fw_cfg.h"
-
-QFWCFG *pc_fw_cfg_init(void);
-
-#endif
diff --git a/tests/libqos/fw_cfg.c b/tests/libqos/fw_cfg.c
index e386ff7ba7..ef00fedf1a 100644
--- a/tests/libqos/fw_cfg.c
+++ b/tests/libqos/fw_cfg.c
@@ -2,15 +2,19 @@
* libqos fw_cfg support
*
* Copyright IBM, Corp. 2012-2013
+ * Copyright (C) 2013 Red Hat Inc.
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
+ * Markus Armbruster <armbru@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include <glib.h>
#include "libqos/fw_cfg.h"
+#include "libqtest.h"
#include "qemu/bswap.h"
void qfw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
@@ -50,3 +54,54 @@ uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key)
return le64_to_cpu(value);
}
+static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
+{
+ writew(fw_cfg->base, key);
+}
+
+static void mm_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
+{
+ uint8_t *ptr = data;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ ptr[i] = readb(fw_cfg->base + 2);
+ }
+}
+
+QFWCFG *mm_fw_cfg_init(uint64_t base)
+{
+ QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
+
+ fw_cfg->base = base;
+ fw_cfg->select = mm_fw_cfg_select;
+ fw_cfg->read = mm_fw_cfg_read;
+
+ return fw_cfg;
+}
+
+static void io_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
+{
+ outw(fw_cfg->base, key);
+}
+
+static void io_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
+{
+ uint8_t *ptr = data;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ ptr[i] = inb(fw_cfg->base + 1);
+ }
+}
+
+QFWCFG *io_fw_cfg_init(uint16_t base)
+{
+ QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
+
+ fw_cfg->base = base;
+ fw_cfg->select = io_fw_cfg_select;
+ fw_cfg->read = io_fw_cfg_read;
+
+ return fw_cfg;
+}
diff --git a/tests/libqos/fw_cfg.h b/tests/libqos/fw_cfg.h
index 44fc42ba11..61b1548b4e 100644
--- a/tests/libqos/fw_cfg.h
+++ b/tests/libqos/fw_cfg.h
@@ -20,6 +20,7 @@ typedef struct QFWCFG QFWCFG;
struct QFWCFG
{
+ uint64_t base;
void (*select)(QFWCFG *fw_cfg, uint16_t key);
void (*read)(QFWCFG *fw_cfg, void *data, size_t len);
};
@@ -31,4 +32,12 @@ uint16_t qfw_cfg_get_u16(QFWCFG *fw_cfg, uint16_t key);
uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key);
uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key);
+QFWCFG *mm_fw_cfg_init(uint64_t base);
+QFWCFG *io_fw_cfg_init(uint16_t base);
+
+static inline QFWCFG *pc_fw_cfg_init(void)
+{
+ return io_fw_cfg_init(0x510);
+}
+
#endif
diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index adc36c4731..db1496c667 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -11,7 +11,7 @@
*/
#include "libqos/malloc-pc.h"
-#include "libqos/fw_cfg-pc.h"
+#include "libqos/fw_cfg.h"
#define NO_QEMU_PROTOS
#include "hw/nvram/fw_cfg.h"
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 879ffe91dc..bb82069f5c 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -171,12 +171,16 @@ void qtest_quit(QTestState *s)
waitpid(pid, &status, 0);
}
+ close(s->fd);
+ close(s->qmp_fd);
+ g_string_free(s->rx, true);
unlink(s->pid_file);
unlink(s->socket_path);
unlink(s->qmp_socket_path);
g_free(s->pid_file);
g_free(s->socket_path);
g_free(s->qmp_socket_path);
+ g_free(s);
}
static void socket_sendf(int fd, const char *fmt, va_list ap)
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 437bda39f3..0f6aade092 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -17,6 +17,7 @@
#ifndef LIBQTEST_H
#define LIBQTEST_H
+#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
@@ -319,6 +320,17 @@ static inline QTestState *qtest_start(const char *args)
}
/**
+ * qtest_end:
+ *
+ * Shut down the QEMU process started by qtest_start().
+ */
+static inline void qtest_end(void)
+{
+ qtest_quit(global_qtest);
+ global_qtest = NULL;
+}
+
+/**
* qmp:
* @fmt...: QMP message to send to qemu
*
diff --git a/tests/test-bitops.c b/tests/test-bitops.c
new file mode 100644
index 0000000000..4e713e4e00
--- /dev/null
+++ b/tests/test-bitops.c
@@ -0,0 +1,75 @@
+/*
+ * Test bitops routines
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <glib.h>
+#include <stdint.h>
+#include "qemu/bitops.h"
+
+typedef struct {
+ uint32_t value;
+ int start;
+ int length;
+ int32_t result;
+} S32Test;
+
+typedef struct {
+ uint64_t value;
+ int start;
+ int length;
+ int64_t result;
+} S64Test;
+
+static const S32Test test_s32_data[] = {
+ { 0x38463983, 4, 4, -8 },
+ { 0x38463983, 12, 8, 0x63 },
+ { 0x38463983, 0, 32, 0x38463983 },
+};
+
+static const S64Test test_s64_data[] = {
+ { 0x8459826734967223, 60, 4, -8 },
+ { 0x8459826734967223, 0, 64, 0x8459826734967223 },
+};
+
+static void test_sextract32(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_s32_data); i++) {
+ const S32Test *test = &test_s32_data[i];
+ int32_t r = sextract32(test->value, test->start, test->length);
+
+ g_assert_cmpint(r, ==, test->result);
+ }
+}
+
+static void test_sextract64(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_s32_data); i++) {
+ const S32Test *test = &test_s32_data[i];
+ int64_t r = sextract64(test->value, test->start, test->length);
+
+ g_assert_cmpint(r, ==, test->result);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(test_s64_data); i++) {
+ const S64Test *test = &test_s64_data[i];
+ int64_t r = sextract64(test->value, test->start, test->length);
+
+ g_assert_cmpint(r, ==, test->result);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/bitops/sextract32", test_sextract32);
+ g_test_add_func("/bitops/sextract64", test_sextract64);
+ return g_test_run();
+}
diff --git a/trace-events b/trace-events
index 0acce7b350..002df83b9d 100644
--- a/trace-events
+++ b/trace-events
@@ -25,18 +25,14 @@
#
# The <format-string> should be a sprintf()-compatible format string.
-# qemu-malloc.c
-g_malloc(size_t size, void *ptr) "size %zu ptr %p"
-g_realloc(void *ptr, size_t size, void *newptr) "ptr %p size %zu newptr %p"
-g_free(void *ptr) "ptr %p"
-
-# osdep.c
+# util/oslib-win32.c
+# util/oslib-posix.c
qemu_memalign(size_t alignment, size_t size, void *ptr) "alignment %zu size %zu ptr %p"
qemu_anon_ram_alloc(size_t size, void *ptr) "size %zu ptr %p"
qemu_vfree(void *ptr) "ptr %p"
qemu_anon_ram_free(void *ptr, size_t size) "ptr %p size %zu"
-# hw/virtio.c
+# hw/virtio/virtio.c
virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"
virtqueue_flush(void *vq, unsigned int count) "vq %p count %u"
virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) "vq %p elem %p in_num %u out_num %u"
@@ -45,13 +41,13 @@ virtio_irq(void *vq) "vq %p"
virtio_notify(void *vdev, void *vq) "vdev %p vq %p"
virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u"
-# hw/virtio-serial-bus.c
+# hw/char/virtio-serial-bus.c
virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u"
virtio_serial_throttle_port(unsigned int port, bool throttle) "port %u, throttle %d"
virtio_serial_handle_control_message(uint16_t event, uint16_t value) "event %u, value %u"
virtio_serial_handle_control_message_port(unsigned int port) "port %u"
-# hw/virtio-console.c
+# hw/char/virtio-console.c
virtio_console_flush_buf(unsigned int port, size_t len, ssize_t ret) "port %u, in_len %zu, out_len %zd"
virtio_console_chr_read(unsigned int port, int size) "port %u, size %d"
virtio_console_chr_event(unsigned int port, int event) "port %u, event %d"
@@ -75,6 +71,8 @@ bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t c
# block/stream.c
stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
+
+# block/commit.c
commit_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
commit_start(void *bs, void *base, void *top, void *s, void *co, void *opaque) "bs %p base %p top %p s %p co %p opaque %p"
@@ -85,7 +83,6 @@ mirror_before_flush(void *s) "s %p"
mirror_before_drain(void *s, int64_t cnt) "s %p dirty count %"PRId64
mirror_before_sleep(void *s, int64_t cnt, int synced) "s %p dirty count %"PRId64" synced %d"
mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_num %"PRId64" nb_sectors %d"
-mirror_cow(void *s, int64_t sector_num) "s %p sector_num %"PRId64
mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d"
mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d"
mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d"
@@ -108,19 +105,19 @@ qmp_block_job_complete(void *job) "job %p"
block_job_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
qmp_block_stream(void *bs, void *job) "bs %p job %p"
-# hw/virtio-blk.c
+# hw/block/virtio-blk.c
virtio_blk_req_complete(void *req, int status) "req %p status %d"
virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
-# hw/dataplane/virtio-blk.c
+# hw/block/dataplane/virtio-blk.c
virtio_blk_data_plane_start(void *s) "dataplane %p"
virtio_blk_data_plane_stop(void *s) "dataplane %p"
virtio_blk_data_plane_process_request(void *s, unsigned int out_num, unsigned int in_num, unsigned int head) "dataplane %p out_num %u in_num %u head %u"
virtio_blk_data_plane_complete_request(void *s, unsigned int head, int ret) "dataplane %p head %u ret %d"
-# hw/dataplane/vring.c
+# hw/virtio/dataplane/vring.c
vring_setup(uint64_t physical, void *desc, void *avail, void *used) "vring physical %#"PRIx64" desc %p avail %p used %p"
# thread-pool.c
@@ -128,10 +125,9 @@ thread_pool_submit(void *pool, void *req, void *opaque) "pool %p req %p opaque %
thread_pool_complete(void *pool, void *req, void *opaque, int ret) "pool %p req %p opaque %p ret %d"
thread_pool_cancel(void *req, void *opaque) "req %p opaque %p"
-# posix-aio-compat.c
+# block/raw-win32.c
+# block/raw-posix.c
paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
-paio_complete(void *acb, void *opaque, int ret) "acb %p opaque %p ret %d"
-paio_cancel(void *acb, void *opaque) "acb %p opaque %p"
# ioport.c
cpu_in(unsigned int addr, unsigned int val) "addr %#x value %u"
@@ -141,29 +137,31 @@ cpu_out(unsigned int addr, unsigned int val) "addr %#x value %u"
# Since requests are raised via monitor, not many tracepoints are needed.
balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
-# hw/apic.c
-apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d"
-apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d trigger_mode %d"
+# hw/intc/apic_common.c
cpu_set_apic_base(uint64_t val) "%016"PRIx64
cpu_get_apic_base(uint64_t val) "%016"PRIx64
-apic_mem_readl(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
-apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
# coalescing
apic_report_irq_delivered(int apic_irq_delivered) "coalescing %d"
apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
-# hw/cs4231.c
+# hw/intc/apic.c
+apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d"
+apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d trigger_mode %d"
+apic_mem_readl(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
+apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
+
+# hw/audio/cs4231.c
cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x"
cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x"
cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x"
-# hw/ds1225y.c
+# hw/nvram/ds1225y.c
nvram_read(uint32_t addr, uint32_t ret) "read addr %d: 0x%02x"
nvram_write(uint32_t addr, uint32_t old, uint32_t val) "write addr %d: 0x%02x -> 0x%02x"
-# hw/eccmemctl.c
+# hw/misc/eccmemctl.c
ecc_mem_writel_mer(uint32_t val) "Write memory enable %08x"
ecc_mem_writel_mdr(uint32_t val) "Write memory delay %08x"
ecc_mem_writel_mfsr(uint32_t val) "Write memory fault status %08x"
@@ -183,26 +181,26 @@ ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x"
ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x"
ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x"
-# hw/fw_cfg.c
+# hw/nvram/fw_cfg.c
fw_cfg_write(void *s, uint8_t value) "%p %d"
fw_cfg_select(void *s, uint16_t key, int ret) "%p key %d = %d"
fw_cfg_read(void *s, uint8_t ret) "%p = %d"
fw_cfg_add_file_dupe(void *s, char *name) "%p %s"
fw_cfg_add_file(void *s, int index, char *name, size_t len) "%p #%d: %s (%zd bytes)"
-# hw/hd-geometry.c
+# hw/block/hd-geometry.c
hd_geometry_lchs_guess(void *bs, int cyls, int heads, int secs) "bs %p LCHS %d %d %d"
hd_geometry_guess(void *bs, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "bs %p CHS %u %u %u trans %d"
-# hw/jazz-led.c
+# hw/display/jazz_led.c
jazz_led_read(uint64_t addr, uint8_t val) "read addr=0x%"PRIx64": 0x%x"
jazz_led_write(uint64_t addr, uint8_t new) "write addr=0x%"PRIx64": 0x%x"
-# hw/lance.c
+# hw/net/lance.c
lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x"
lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x"
-# hw/slavio_intctl.c
+# hw/intc/slavio_intctl.c
slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = %x"
slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = %x"
slavio_intctl_mem_writel_clear(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Cleared cpu %d irq mask %x, curmask %x"
@@ -216,7 +214,7 @@ slavio_check_interrupts(uint32_t pending, uint32_t intregm_disabled) "pending %x
slavio_set_irq(uint32_t target_cpu, int irq, uint32_t pil, int level) "Set cpu %d irq %d -> pil %d level %d"
slavio_set_timer_irq_cpu(int cpu, int level) "Set cpu %d local timer level %d"
-# hw/slavio_misc.c
+# hw/misc/slavio_misc.c
slavio_misc_update_irq_raise(void) "Raise IRQ"
slavio_misc_update_irq_lower(void) "Lower IRQ"
slavio_set_power_fail(int power_failing, uint8_t config) "Power fail: %d, config: %d"
@@ -237,7 +235,7 @@ slavio_sysctrl_mem_readl(uint32_t ret) "Read system control %08x"
slavio_led_mem_writew(uint32_t val) "Write diagnostic LED %04x"
slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x"
-# hw/slavio_timer.c
+# hw/timer/slavio_timer.c
slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x"
slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x"
slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64
@@ -252,7 +250,7 @@ slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d cha
slavio_timer_mem_writel_mode_invalid(void) "not system timer"
slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64
-# hw/sparc32_dma.c
+# hw/dma/sparc32_dma.c
ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64
ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64
sparc32_dma_set_irq_raise(void) "Raise IRQ"
@@ -264,13 +262,13 @@ sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg
sparc32_dma_enable_raise(void) "Raise DMA enable"
sparc32_dma_enable_lower(void) "Lower DMA enable"
-# hw/sun4m.c
+# hw/sparc/sun4m.c
sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d"
sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d"
sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d"
sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d"
-# hw/sun4m_iommu.c
+# hw/dma/sun4m_iommu.c
sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x"
sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x"
sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64
@@ -311,7 +309,6 @@ usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ %08x: next %0
usb_ehci_port_attach(uint32_t port, const char *owner, const char *device) "attach port #%d, owner %s, device %s"
usb_ehci_port_detach(uint32_t port, const char *owner) "detach port #%d, owner %s"
usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
-usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s"
usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x"
@@ -429,6 +426,7 @@ usb_uas_tmf_logical_unit_reset(int addr, uint16_t tag, int lun) "dev %d, tag 0x%
usb_uas_tmf_unsupported(int addr, uint16_t tag, uint32_t function) "dev %d, tag 0x%x, function 0x%x"
# hw/usb/host-linux.c
+# hw/usb/host-libusb.c
usb_host_open_started(int bus, int addr) "dev %d:%d"
usb_host_open_success(int bus, int addr) "dev %d:%d"
usb_host_open_failure(int bus, int addr) "dev %d:%d"
@@ -468,7 +466,7 @@ usb_host_parse_endpoint(int bus, int addr, int ep, const char *dir, const char *
usb_host_parse_unknown(int bus, int addr, int len, int type) "dev %d:%d, len %d, type %d"
usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s"
-# hw/scsi-bus.c
+# hw/scsi/scsi-bus.c
scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_cancel(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
@@ -490,6 +488,9 @@ scsi_request_sense(int target, int lun, int tag) "target %d lun %d tag %d"
vm_state_notify(int running, int reason) "running %d reason %d"
load_file(const char *name, const char *path) "name %s location %s"
runstate_set(int new_state) "new state %d"
+g_malloc(size_t size, void *ptr) "size %zu ptr %p"
+g_realloc(void *ptr, size_t size, void *newptr) "ptr %p size %zu newptr %p"
+g_free(void *ptr) "ptr %p"
# block/qcow2.c
qcow2_writev_start_req(void *co, int64_t sector, int nb_sectors) "co %p sector %" PRIx64 " nb_sectors %d"
@@ -498,6 +499,7 @@ qcow2_writev_start_part(void *co) "co %p"
qcow2_writev_done_part(void *co, int cur_nr_sectors) "co %p cur_nr_sectors %d"
qcow2_writev_data(void *co, uint64_t offset) "co %p offset %" PRIx64
+# block/qcow2-cluster.c
qcow2_alloc_clusters_offset(void *co, uint64_t offset, int n_start, int n_end) "co %p offet %" PRIx64 " n_start %d n_end %d"
qcow2_handle_copied(void *co, uint64_t guest_offset, uint64_t host_offset, uint64_t bytes) "co %p guest_offet %" PRIx64 " host_offset %" PRIx64 " bytes %" PRIx64
qcow2_handle_alloc(void *co, uint64_t guest_offset, uint64_t host_offset, uint64_t bytes) "co %p guest_offet %" PRIx64 " host_offset %" PRIx64 " bytes %" PRIx64
@@ -511,6 +513,7 @@ qcow2_l2_allocate_write_l2(void *bs, int l1_index) "bs %p l1_index %d"
qcow2_l2_allocate_write_l1(void *bs, int l1_index) "bs %p l1_index %d"
qcow2_l2_allocate_done(void *bs, int l1_index, int ret) "bs %p l1_index %d ret %d"
+# block/qcow2-cache.c
qcow2_cache_get(void *co, int c, uint64_t offset, bool read_from_disk) "co %p is_l2_cache %d offset %" PRIx64 " read_from_disk %d"
qcow2_cache_get_replace_entry(void *co, int c, int i) "co %p is_l2_cache %d index %d"
qcow2_cache_get_read(void *co, int c, int i) "co %p is_l2_cache %d index %d"
@@ -542,11 +545,11 @@ qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t o
qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
-# hw/g364fb.c
+# hw/display/g364fb.c
g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x"
g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x"
-# hw/grlib_gptimer.c
+# hw/timer/grlib_gptimer.c
grlib_gptimer_enable(int id, uint32_t count) "timer:%d set count 0x%x and run"
grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable config 0x%x"
grlib_gptimer_restart(int id, uint32_t reload) "timer:%d reload val: 0x%x"
@@ -555,19 +558,19 @@ grlib_gptimer_hit(int id) "timer:%d HIT"
grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
-# hw/grlib_irqmp.c
+# hw/intc/grlib_irqmp.c
grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x"
grlib_irqmp_ack(int intno) "interrupt:%d"
grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64
grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
-# hw/grlib_apbuart.c
+# hw/char/grlib_apbuart.c
grlib_apbuart_event(int event) "event:%d"
grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64""
-# hw/leon3.c
+# hw/sparc/leon3.c
leon3_set_irq(int intno) "Set CPU IRQ %d"
leon3_reset_irq(int intno) "Reset CPU IRQ %d"
@@ -578,7 +581,7 @@ spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
spice_vmc_event(int event) "spice vmc event %d"
-# hw/lm32_pic.c
+# hw/intc/lm32_pic.c
lm32_pic_raise_irq(void) "Raise CPU interrupt"
lm32_pic_lower_irq(void) "Lower CPU interrupt"
lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d"
@@ -587,27 +590,27 @@ lm32_pic_set_ip(uint32_t ip) "ip 0x%08x"
lm32_pic_get_im(uint32_t im) "im 0x%08x"
lm32_pic_get_ip(uint32_t ip) "ip 0x%08x"
-# hw/lm32_juart.c
+# hw/char/lm32_juart.c
lm32_juart_get_jtx(uint32_t value) "jtx 0x%08x"
lm32_juart_set_jtx(uint32_t value) "jtx 0x%08x"
lm32_juart_get_jrx(uint32_t value) "jrx 0x%08x"
lm32_juart_set_jrx(uint32_t value) "jrx 0x%08x"
-# hw/lm32_timer.c
+# hw/timer/lm32_timer.c
lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
lm32_timer_hit(void) "timer hit"
lm32_timer_irq_state(int level) "irq state %d"
-# hw/lm32_uart.c
+# hw/char/lm32_uart.c
lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
lm32_uart_irq_state(int level) "irq state %d"
-# hw/lm32_sys.c
+# hw/misc/lm32_sys.c
lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-# hw/megasas.c
+# hw/scsi/megasas.c
megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " "
megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at %" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x"
megasas_initq_map_failed(int frame) "scmd %d: failed to map queue"
@@ -617,11 +620,9 @@ megasas_qf_new(unsigned int index, void *cmd) "return new frame %x cmd %p"
megasas_qf_failed(unsigned long pa) "all frames busy for frame %lx"
megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int tail, int busy) "enqueue frame %x count %d context %" PRIx64 " tail %x busy %d"
megasas_qf_update(unsigned int head, unsigned int busy) "update reply queue head %x busy %d"
-megasas_qf_dequeue(unsigned int index) "dequeue frame %x"
megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu"
megasas_qf_complete_noirq(uint64_t context) "context %" PRIx64 " "
megasas_qf_complete(uint64_t context, unsigned int tail, unsigned int offset, int busy, unsigned int doorbell) "context %" PRIx64 " tail %x offset %d busy %d doorbell %x"
-megasas_handle_frame(const char *cmd, uint64_t addr, uint64_t context, uint32_t count) "MFI cmd %s addr %" PRIx64 " context %" PRIx64 " count %d"
megasas_frame_busy(uint64_t addr) "frame %" PRIx64 " busy"
megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: Unhandled MFI cmd %x"
megasas_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned long size) "%s dev %x/%x/%x sdev %p xfer %lu"
@@ -644,8 +645,6 @@ megasas_io_write_start(int cmd, unsigned long lba, unsigned long count, unsigned
megasas_io_complete(int cmd, uint32_t len) "scmd %d: %d bytes completed"
megasas_io_read(int cmd, int bytes, int len, unsigned long offset) "scmd %d: %d/%d bytes, iov offset %lu"
megasas_io_write(int cmd, int bytes, int len, unsigned long offset) "scmd %d: %d/%d bytes, iov offset %lu"
-megasas_io_continue(int cmd, int bytes) "scmd %d: %d bytes left"
-megasas_iovec_map_failed(int cmd, int index, unsigned long iov_size) "scmd %d: iovec %d size %lu"
megasas_iovec_sgl_overflow(int cmd, int index, int limit) "scmd %d: iovec count %d limit %d"
megasas_iovec_sgl_underflow(int cmd, int index) "scmd %d: iovec count %d"
megasas_iovec_sgl_invalid(int cmd, int index, uint64_t pa, uint32_t len) "scmd %d: element %d pa %" PRIx64 " len %u"
@@ -660,7 +659,6 @@ megasas_dcmd_internal_invalid(int cmd, int opcode) "scmd %d: Invalid internal DC
megasas_dcmd_unhandled(int cmd, int opcode, int len) "scmd %d: opcode %x, len %d"
megasas_dcmd_zero_sge(int cmd) "scmd %d: zero DCMD sge count"
megasas_dcmd_invalid_sge(int cmd, int count) "scmd %d: invalid DCMD sge count %d"
-megasas_dcmd_map_failed(int cmd) "scmd %d: Failed to map DCMD buffer"
megasas_dcmd_invalid_xfer_len(int cmd, unsigned long size, unsigned long max) "scmd %d: invalid xfer len %ld, max %ld"
megasas_dcmd_enter(int cmd, const char *dcmd, int len) "scmd %d: DCMD %s len %d"
megasas_dcmd_dummy(int cmd, unsigned long size) "scmd %d: DCMD dummy xfer len %ld"
@@ -686,7 +684,7 @@ megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx"
megasas_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
megasas_mmio_invalid_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
-# hw/milkymist-ac97.c
+# hw/audio/milkymist-ac97.c
milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
@@ -698,15 +696,15 @@ milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
-# hw/milkymist-hpdmc.c
+# hw/misc/milkymist-hpdmc.c
milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
-# hw/milkymist-memcard.c
+# hw/sd/milkymist-memcard.c
milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
-# hw/milkymist-minimac2.c
+# hw/net/milkymist-minimac2.c
milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
@@ -719,21 +717,20 @@ milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX"
milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX"
milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX"
-# hw/milkymist-pfpu.c
+# hw/misc/milkymist-pfpu.c
milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x"
milkymist_pfpu_pulse_irq(void) "Pulse IRQ"
-# hw/milkymist-softusb.c
+# hw/input/milkymist-softusb.c
milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_softusb_mevt(uint8_t m) "m %d"
milkymist_softusb_kevt(uint8_t m) "m %d"
-milkymist_softusb_mouse_event(int dx, int dy, int dz, int bs) "dx %d dy %d dz %d bs %02x"
milkymist_softusb_pulse_irq(void) "Pulse IRQ"
-# hw/milkymist-sysctl.c
+# hw/timer/milkymist-sysctl.c
milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_sysctl_icap_write(uint32_t value) "value %08x"
@@ -744,30 +741,30 @@ milkymist_sysctl_stop_timer1(void) "Stop timer1"
milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0"
milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1"
-# hw/milkymist-tmu2.c
+# hw/display/milkymist-tmu2.c
milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_tmu2_start(void) "Start TMU"
milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
-# hw/milkymist-uart.c
+# hw/char/milkymist-uart.c
milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_uart_raise_irq(void) "Raise IRQ"
milkymist_uart_lower_irq(void) "Lower IRQ"
-# hw/milkymist-vgafb.c
+# hw/display/milkymist-vgafb.c
milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
-# hw/mipsnet.c
+# hw/net/mipsnet.c
mipsnet_send(uint32_t size) "sending len=%u"
mipsnet_receive(uint32_t size) "receiving len=%u"
mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x"
mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64 ""
mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)"
-# hw/pc87312.c
+# hw/isa/pc87312.c
pc87312_io_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
pc87312_io_write(uint32_t addr, uint32_t val) "write addr=%x val=%x"
pc87312_info_floppy(uint32_t base) "base 0x%x"
@@ -818,10 +815,8 @@ xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "
xen_map_cache(uint64_t phys_addr) "want %#"PRIx64
xen_remap_bucket(uint64_t index) "index %#"PRIx64
xen_map_cache_return(void* ptr) "%p"
-xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64
-xen_unmap_block(void* addr, unsigned long size) "%p, size %#lx"
-# hw/xen_platform.c
+# hw/xen/xen_platform.c
xen_platform_log(char *s) "xen platform: %s"
# qemu-coroutine.c
@@ -837,7 +832,7 @@ qemu_co_mutex_lock_return(void *mutex, void *self) "mutex %p self %p"
qemu_co_mutex_unlock_entry(void *mutex, void *self) "mutex %p self %p"
qemu_co_mutex_unlock_return(void *mutex, void *self) "mutex %p self %p"
-# hw/escc.c
+# hw/char/escc.c
escc_put_queue(char channel, int b) "channel %c put: 0x%02x"
escc_get_queue(char channel, int val) "channel %c get 0x%02x"
escc_update_irq(int irq) "IRQ = %d"
@@ -858,7 +853,7 @@ iscsi_aio_writev(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque,
iscsi_aio_read16_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
iscsi_aio_readv(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
-# hw/esp.c
+# hw/scsi/esp.c
esp_error_fifo_overrun(void) "FIFO overrun"
esp_error_unhandled_command(uint32_t val) "unhandled command (%2.2x)"
esp_error_invalid_write(uint32_t val, uint32_t addr) "invalid write of 0x%02x at [0x%x]"
@@ -893,6 +888,8 @@ esp_mem_writeb_cmd_selatn(uint32_t val) "Select with ATN (%2.2x)"
esp_mem_writeb_cmd_selatns(uint32_t val) "Select with ATN & stop (%2.2x)"
esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)"
esp_mem_writeb_cmd_dissel(uint32_t val) "Disable selection (%2.2x)"
+
+# hw/scsi/esp-pci.c
esp_pci_error_invalid_dma_direction(void) "invalid DMA transfer direction"
esp_pci_error_invalid_read(uint32_t reg) "read access outside bounds (reg 0x%x)"
esp_pci_error_invalid_write(uint32_t reg) "write access outside bounds (reg 0x%x)"
@@ -915,7 +912,7 @@ monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
monitor_protocol_event_queue(uint32_t event, void *data, uint64_t rate, uint64_t last, uint64_t now) "event=%d data=%p rate=%" PRId64 " last=%" PRId64 " now=%" PRId64
monitor_protocol_event_throttle(uint32_t event, uint64_t rate) "event=%d rate=%" PRId64
-# hw/opencores_eth.c
+# hw/net/opencores_eth.c
open_eth_mii_write(unsigned idx, uint16_t v) "MII[%02x] <- %04x"
open_eth_mii_read(unsigned idx, uint16_t v) "MII[%02x] -> %04x"
open_eth_update_irq(uint32_t v) "IRQ <- %x"
@@ -985,10 +982,12 @@ mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, u
mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at %"PRIx64" -> %"PRIx64", mmu_idx=%d tl=%d primary context=%"PRIx64" secondary context=%"PRIx64""
-# target-sparc/int_helper.c
+# target-sparc/int64_helper.c
int_helper_set_softint(uint32_t softint) "new %08x"
int_helper_clear_softint(uint32_t softint) "new %08x"
int_helper_write_softint(uint32_t softint) "new %08x"
+
+# target-sparc/int32_helper.c
int_helper_icache_freeze(void) "Instruction cache: freeze"
int_helper_dcache_freeze(void) "Data cache: freeze"
@@ -1007,7 +1006,7 @@ dma_complete(void *dbs, int ret, void *cb) "dbs=%p ret=%d cb=%p"
dma_bdrv_cb(void *dbs, int ret) "dbs=%p ret=%d"
dma_map_wait(void *dbs) "dbs=%p"
-# console.h
+# ui/console.c
console_gfx_new(void) ""
console_txt_new(int w, int h) "%dx%d"
console_select(int nr) "%d"
@@ -1017,9 +1016,9 @@ displaysurface_create_from(void *display_surface, int w, int h, int bpp, int swa
displaysurface_free(void *display_surface) "surface=%p"
displaychangelistener_register(void *dcl, const char *name) "%p [ %s ]"
displaychangelistener_unregister(void *dcl, const char *name) "%p [ %s ]"
-
-# vga.c
ppm_save(const char *filename, void *display_surface) "%s surface=%p"
+
+# hw/display/vmware_vga.c
vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_palette_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
@@ -1029,15 +1028,15 @@ vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp"
# savevm.c
-
savevm_section_start(void) ""
savevm_section_end(unsigned int section_id) "section_id %u"
# arch_init.c
migration_bitmap_sync_start(void) ""
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64""
+migration_throttle(void) ""
-# hw/qxl.c
+# hw/display/qxl.c
disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d"
disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u"
qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %ux%u mem=%" PRIx64 " %u,%u"
@@ -1075,14 +1074,6 @@ qxl_ring_res_push_rest(int qid, uint32_t ring_has, uint32_t ring_size, uint32_t
qxl_ring_res_put(int qid, uint32_t free_res) "%d #res=%d"
qxl_set_mode(int qid, int modenr, uint32_t x_res, uint32_t y_res, uint32_t bits, uint64_t devmem) "%d mode=%d [ x=%d y=%d @ bpp=%d devmem=0x%" PRIx64 " ]"
qxl_soft_reset(int qid) "%d"
-qemu_spice_add_memslot(int qid, uint32_t slot_id, unsigned long virt_start, unsigned long virt_end, int async) "%d %u: host virt 0x%lx - 0x%lx async=%d"
-qemu_spice_del_memslot(int qid, uint32_t gid, uint32_t slot_id) "%d gid=%u sid=%u"
-qemu_spice_create_primary_surface(int qid, uint32_t sid, void *surface, int async) "%d sid=%u surface=%p async=%d"
-qemu_spice_destroy_primary_surface(int qid, uint32_t sid, int async) "%d sid=%u async=%d"
-qemu_spice_wakeup(uint32_t qid) "%d"
-qemu_spice_start(uint32_t qid) "%d"
-qemu_spice_stop(uint32_t qid) "%d"
-qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "lr %d -> %d, tb -> %d -> %d"
qxl_spice_destroy_surfaces_complete(int qid) "%d"
qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d"
qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d"
@@ -1107,13 +1098,21 @@ qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d"
qxl_client_monitors_config_crc(int qid, unsigned size, uint32_t crc32) "%d %u %u"
qxl_set_client_capabilities_unsupported_by_revision(int qid, int revision) "%d revision=%d"
-# hw/qxl-render.c
+# ui/spice-display.c
+qemu_spice_add_memslot(int qid, uint32_t slot_id, unsigned long virt_start, unsigned long virt_end, int async) "%d %u: host virt 0x%lx - 0x%lx async=%d"
+qemu_spice_del_memslot(int qid, uint32_t gid, uint32_t slot_id) "%d gid=%u sid=%u"
+qemu_spice_create_primary_surface(int qid, uint32_t sid, void *surface, int async) "%d sid=%u surface=%p async=%d"
+qemu_spice_destroy_primary_surface(int qid, uint32_t sid, int async) "%d sid=%u async=%d"
+qemu_spice_wakeup(uint32_t qid) "%d"
+qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "lr %d -> %d, tb -> %d -> %d"
+
+# hw/display/qxl-render.c
qxl_render_blit_guest_primary_initialized(void) ""
qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]"
qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d"
qxl_render_update_area_done(void *cookie) "%p"
-# hw/spapr_pci.c
+# hw/ppc/spapr_pci.c
spapr_pci_msi(const char *msg, uint32_t n, uint32_t ca) "%s (device#%d, cfg=%x)"
spapr_pci_msi_setup(const char *name, unsigned vector, uint64_t addr) "dev\"%s\" vector %u, addr=%"PRIx64
spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %u"
@@ -1121,7 +1120,7 @@ spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "q
spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
-# hw/xics.c
+# hw/ppc/xics.c
xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=%#x"
xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR %#"PRIx32"->%#"PRIx32
xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR %#"PRIx32" new XIRR %#"PRIx32
@@ -1134,7 +1133,7 @@ xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_
xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]"
xics_ics_eoi(int nr) "ics_eoi: irq %#x"
-# hbitmap.c
+# util/hbitmap.c
hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx"
hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64
hbitmap_set(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64
diff --git a/translate-all.c b/translate-all.c
index e8683d2c66..3b5fc7c901 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1148,7 +1148,8 @@ void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
#if !defined(CONFIG_SOFTMMU)
static void tb_invalidate_phys_page(tb_page_addr_t addr,
- uintptr_t pc, void *puc)
+ uintptr_t pc, void *puc,
+ bool locked)
{
TranslationBlock *tb;
PageDesc *p;
@@ -1206,6 +1207,9 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr,
itself */
cpu->current_tb = NULL;
tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
+ if (locked) {
+ mmap_unlock();
+ }
cpu_resume_from_signal(env, puc);
}
#endif
@@ -1723,7 +1727,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
if (!(p->flags & PAGE_WRITE) &&
(flags & PAGE_WRITE) &&
p->first_tb) {
- tb_invalidate_phys_page(addr, 0, NULL);
+ tb_invalidate_phys_page(addr, 0, NULL, false);
}
p->flags = flags;
}
@@ -1818,7 +1822,7 @@ int page_unprotect(target_ulong address, uintptr_t pc, void *puc)
/* and since the content will be modified, we must invalidate
the corresponding translated code. */
- tb_invalidate_phys_page(addr, pc, puc);
+ tb_invalidate_phys_page(addr, pc, puc, true);
#ifdef DEBUG_TB_CHECK
tb_invalidate_check(addr);
#endif
diff --git a/ui/gtk.c b/ui/gtk.c
index 4fb66a3734..c38146f80f 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -98,6 +98,10 @@ static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
#define GDK_KEY_minus GDK_minus
#endif
+#define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK)
+#define IGNORE_MODIFIER_MASK \
+ (GDK_MODIFIER_MASK & ~(GDK_LOCK_MASK | GDK_MOD2_MASK))
+
static const int modifier_keycode[] = {
/* shift, control, alt keys, meta keys, both left & right */
0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8, 0xdb, 0xdd,
@@ -473,22 +477,10 @@ static void gd_mouse_mode_change(Notifier *notify, void *data)
static gboolean gd_window_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
{
GtkDisplayState *s = opaque;
- GtkAccelGroupEntry *entries;
- guint n_entries = 0;
- gboolean propagate_accel = TRUE;
gboolean handled = FALSE;
- entries = gtk_accel_group_query(s->accel_group, key->keyval,
- key->state, &n_entries);
- if (n_entries) {
- const char *quark = g_quark_to_string(entries[0].accel_path_quark);
-
- if (gd_is_grab_active(s) && strstart(quark, "<QEMU>/File/", NULL)) {
- propagate_accel = FALSE;
- }
- }
-
- if (!handled && propagate_accel) {
+ if (!gd_is_grab_active(s) ||
+ (key->state & IGNORE_MODIFIER_MASK) == HOTKEY_MODIFIERS) {
handled = gtk_window_activate_key(GTK_WINDOW(widget), key);
}
if (handled) {
@@ -1197,7 +1189,7 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL
vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, label);
group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path);
- gtk_accel_map_add_entry(path, GDK_KEY_2 + index, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_accel_map_add_entry(path, GDK_KEY_2 + index, HOTKEY_MODIFIERS);
vc->terminal = vte_terminal_new();
@@ -1354,7 +1346,8 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
gtk_image_menu_item_new_from_stock(GTK_STOCK_FULLSCREEN, NULL);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item),
"<QEMU>/View/Full Screen");
- gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f,
+ HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->full_screen_item);
separator = gtk_separator_menu_item_new();
@@ -1363,19 +1356,22 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item),
"<QEMU>/View/Zoom In");
- gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus,
+ HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_in_item);
s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item),
"<QEMU>/View/Zoom Out");
- gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus,
+ HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_out_item);
s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item),
"<QEMU>/View/Zoom Fixed");
- gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0,
+ HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_fixed_item);
s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic(_("Zoom To _Fit"));
@@ -1390,7 +1386,8 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
s->grab_item = gtk_check_menu_item_new_with_mnemonic(_("_Grab Input"));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item),
"<QEMU>/View/Grab Input");
- gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g,
+ HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->grab_item);
separator = gtk_separator_menu_item_new();
@@ -1400,7 +1397,7 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
"<QEMU>/View/VGA");
- gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+ gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, HOTKEY_MODIFIERS);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->vga_item);
for (i = 0; i < nb_vcs; i++) {
diff --git a/user-exec.c b/user-exec.c
index d45ca8e877..82bfa66ce3 100644
--- a/user-exec.c
+++ b/user-exec.c
@@ -95,6 +95,10 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
return 1;
}
+ /* Convert forcefully to guest address space, invalid addresses
+ are still valid segv ones */
+ address = h2g_nocheck(address);
+
env = current_cpu->env_ptr;
/* see if it is an MMU fault */
ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX);