aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS15
-rw-r--r--Makefile5
-rw-r--r--Makefile.objs5
-rw-r--r--arch_init.c52
-rw-r--r--backends/baum.c4
-rw-r--r--block.c39
-rw-r--r--block/gluster.c159
-rw-r--r--block/iscsi.c142
-rw-r--r--block/mirror.c3
-rw-r--r--block/quorum.c9
-rw-r--r--block/raw-posix.c14
-rw-r--r--block/raw-win32.c14
-rw-r--r--block/vmdk.c2
-rw-r--r--blockdev.c15
-rwxr-xr-xconfigure164
-rw-r--r--cpus.c25
-rw-r--r--default-configs/ppc-softmmu.mak1
-rw-r--r--default-configs/s390x-softmmu.mak1
-rw-r--r--default-configs/sparc-softmmu.mak1
-rw-r--r--disas/libvixl/a64/disasm-a64.cc20
-rw-r--r--docs/qmp/qmp-events.txt75
-rw-r--r--dump.c960
-rw-r--r--exec.c4
-rw-r--r--fsdev/Makefile.objs4
-rw-r--r--fsdev/virtfs-proxy-helper.c2
-rw-r--r--hmp.c5
-rw-r--r--hw/9pfs/cofs.c48
-rw-r--r--hw/9pfs/virtio-9p-handle.c9
-rw-r--r--hw/9pfs/virtio-9p-local.c288
-rw-r--r--hw/9pfs/virtio-9p-posix-acl.c52
-rw-r--r--hw/9pfs/virtio-9p-xattr-user.c27
-rw-r--r--hw/9pfs/virtio-9p-xattr.c9
-rw-r--r--hw/9pfs/virtio-9p-xattr.h27
-rw-r--r--hw/9pfs/virtio-9p.h6
-rw-r--r--hw/Makefile.objs2
-rw-r--r--hw/arm/musicpal.c6
-rw-r--r--hw/arm/omap1.c24
-rw-r--r--hw/arm/pxa2xx.c6
-rw-r--r--hw/arm/pxa2xx_gpio.c2
-rw-r--r--hw/arm/pxa2xx_pic.c4
-rw-r--r--hw/block/dataplane/virtio-blk.c2
-rw-r--r--hw/core/loader.c30
-rw-r--r--hw/core/qdev.c20
-rw-r--r--hw/display/Makefile.objs1
-rw-r--r--hw/display/blizzard.c2
-rw-r--r--hw/display/cg3.c385
-rw-r--r--hw/display/cirrus_vga.c4
-rw-r--r--hw/display/exynos4210_fimd.c2
-rw-r--r--hw/display/g364fb.c2
-rw-r--r--hw/display/jazz_led.c2
-rw-r--r--hw/display/milkymist-vgafb.c2
-rw-r--r--hw/display/omap_lcdc.c2
-rw-r--r--hw/display/pl110.c2
-rw-r--r--hw/display/pxa2xx_lcd.c2
-rw-r--r--hw/display/qxl.c4
-rw-r--r--hw/display/sm501.c2
-rw-r--r--hw/display/ssd0303.c2
-rw-r--r--hw/display/ssd0323.c2
-rw-r--r--hw/display/tc6393xb.c2
-rw-r--r--hw/display/tcx.c4
-rw-r--r--hw/display/vga-isa-mm.c2
-rw-r--r--hw/display/vga-isa.c2
-rw-r--r--hw/display/vga-pci.c2
-rw-r--r--hw/display/vmware_vga.c2
-rw-r--r--hw/display/xenfb.c2
-rw-r--r--hw/i386/acpi-build.c143
-rw-r--r--hw/i386/acpi-dsdt.dsl33
-rw-r--r--hw/i386/acpi-dsdt.hex.generated224
-rw-r--r--hw/i386/pc_piix.c8
-rw-r--r--hw/i386/q35-acpi-dsdt.dsl25
-rw-r--r--hw/i386/q35-acpi-dsdt.hex.generated128
-rw-r--r--hw/i386/ssdt-pcihp.dsl50
-rw-r--r--hw/i386/ssdt-pcihp.hex.generated161
-rw-r--r--hw/ide/ahci.h10
-rw-r--r--hw/input/pckbd.c2
-rw-r--r--hw/intc/Makefile.objs1
-rw-r--r--hw/intc/ioapic.c3
-rw-r--r--hw/intc/openpic_kvm.c2
-rw-r--r--hw/intc/s390_flic.c322
-rw-r--r--hw/intc/xics.c15
-rw-r--r--hw/intc/xics_kvm.c10
-rw-r--r--hw/moxie/moxiesim.c2
-rw-r--r--hw/net/Makefile.objs3
-rw-r--r--hw/net/fsl_etsec/etsec.c465
-rw-r--r--hw/net/fsl_etsec/etsec.h174
-rw-r--r--hw/net/fsl_etsec/miim.c146
-rw-r--r--hw/net/fsl_etsec/registers.c295
-rw-r--r--hw/net/fsl_etsec/registers.h320
-rw-r--r--hw/net/fsl_etsec/rings.c650
-rw-r--r--hw/net/spapr_llan.c2
-rw-r--r--hw/net/virtio-net.c7
-rw-r--r--hw/pci-host/pam.c2
-rw-r--r--hw/pci/pcie.c16
-rw-r--r--hw/ppc/e500.c7
-rw-r--r--hw/ppc/ppc.c22
-rw-r--r--hw/ppc/spapr.c56
-rw-r--r--hw/ppc/spapr_hcall.c87
-rw-r--r--hw/ppc/spapr_iommu.c37
-rw-r--r--hw/ppc/spapr_pci.c15
-rw-r--r--hw/ppc/spapr_rtas.c14
-rw-r--r--hw/ppc/virtex_ml507.c34
-rw-r--r--hw/s390x/css.c10
-rw-r--r--hw/s390x/css.h2
-rw-r--r--hw/s390x/event-facility.c93
-rw-r--r--hw/s390x/ipl.c25
-rw-r--r--hw/s390x/s390-virtio-ccw.c8
-rw-r--r--hw/s390x/s390-virtio-hcall.c14
-rw-r--r--hw/s390x/s390-virtio.c2
-rw-r--r--hw/s390x/sclp.c69
-rw-r--r--hw/s390x/virtio-ccw.c102
-rw-r--r--hw/s390x/virtio-ccw.h4
-rw-r--r--hw/scsi/scsi-bus.c7
-rw-r--r--hw/scsi/scsi-disk.c29
-rw-r--r--hw/scsi/scsi-generic.c2
-rw-r--r--hw/scsi/spapr_vscsi.c61
-rw-r--r--hw/sparc/sun4m.c62
-rw-r--r--hw/ssi/xilinx_spips.c4
-rw-r--r--hw/timer/slavio_timer.c25
-rw-r--r--hw/unicore32/puv3.c2
-rw-r--r--hw/usb/ccid-card-emulated.c8
-rw-r--r--include/exec/cpu-defs.h1
-rw-r--r--include/exec/memory.h6
-rw-r--r--include/hw/boards.h6
-rw-r--r--include/hw/elf_ops.h19
-rw-r--r--include/hw/loader.h6
-rw-r--r--include/hw/nvram/openbios_firmware_abi.h2
-rw-r--r--include/hw/qdev-core.h2
-rw-r--r--include/hw/s390x/event-facility.h19
-rw-r--r--include/hw/s390x/s390_flic.h33
-rw-r--r--include/hw/s390x/sclp.h24
-rw-r--r--include/hw/scsi/scsi.h4
-rw-r--r--include/hw/xen/xen.h3
-rw-r--r--include/qapi/qmp/qerror.h2
-rw-r--r--include/qapi/qmp/qjson.h2
-rw-r--r--include/qemu/bswap.h10
-rw-r--r--include/qemu/host-utils.h30
-rw-r--r--include/qemu/thread.h3
-rw-r--r--include/qom/cpu.h3
-rw-r--r--include/sysemu/dump.h138
-rw-r--r--include/sysemu/kvm.h3
-rw-r--r--include/sysemu/qemumachine.h16
-rw-r--r--include/sysemu/qtest.h3
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--include/ui/console.h33
-rw-r--r--include/ui/input.h56
-rw-r--r--kvm-all.c17
-rw-r--r--kvm-stub.c3
-rw-r--r--libcacard/vscclient.c2
-rw-r--r--linux-headers/asm-s390/kvm.h19
-rw-r--r--linux-headers/linux/kvm.h66
-rw-r--r--linux-user/alpha/syscall.h1
-rw-r--r--linux-user/arm/syscall.h1
-rw-r--r--linux-user/cris/syscall.h2
-rw-r--r--linux-user/i386/syscall.h1
-rw-r--r--linux-user/m68k/syscall.h2
-rw-r--r--linux-user/main.c22
-rw-r--r--linux-user/microblaze/syscall.h2
-rw-r--r--linux-user/mips/syscall.h1
-rw-r--r--linux-user/mips64/syscall.h1
-rw-r--r--linux-user/openrisc/syscall.h1
-rw-r--r--linux-user/ppc/syscall.h1
-rw-r--r--linux-user/s390x/syscall.h1
-rw-r--r--linux-user/sh4/syscall.h1
-rw-r--r--linux-user/signal.c26
-rw-r--r--linux-user/sparc/syscall.h1
-rw-r--r--linux-user/sparc64/syscall.h1
-rw-r--r--linux-user/syscall.c120
-rw-r--r--linux-user/syscall_defs.h7
-rw-r--r--linux-user/unicore32/syscall.h1
-rw-r--r--linux-user/x86_64/syscall.h1
-rw-r--r--memory.c2
-rw-r--r--migration.c2
-rw-r--r--monitor.c35
-rw-r--r--pc-bios/QEMU,cgthree.binbin0 -> 850 bytes
-rw-r--r--pc-bios/README4
-rw-r--r--pc-bios/openbios-ppcbin729912 -> 734008 bytes
-rw-r--r--pc-bios/openbios-sparc32bin381512 -> 381512 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1598376 -> 1598376 bytes
-rw-r--r--pc-bios/s390-ccw.imgbin9336 -> 9336 bytes
-rw-r--r--pc-bios/s390-ccw/main.c3
-rw-r--r--pc-bios/s390-ccw/virtio.c1
-rw-r--r--qapi-schema.json137
-rw-r--r--qapi/opts-visitor.c4
-rw-r--r--qapi/qapi-dealloc-visitor.c4
-rw-r--r--qemu-file.c2
-rw-r--r--qemu-img.c26
-rw-r--r--qemu-options.hx7
-rw-r--r--qga/main.c1
-rw-r--r--qmp-commands.hx27
-rw-r--r--qmp.c4
-rw-r--r--qtest.c2
m---------roms/openbios0
-rw-r--r--savevm.c12
-rw-r--r--scripts/qapi-commands.py24
-rw-r--r--scripts/qapi-types.py4
-rw-r--r--scripts/qapi-visit.py20
-rw-r--r--scripts/qapi.py4
-rwxr-xr-xscripts/qmp/qmp-shell20
-rw-r--r--scripts/qmp/qmp.py7
-rw-r--r--stubs/gdbstub.c4
-rw-r--r--target-arm/cpu.h4
-rw-r--r--target-arm/helper.c91
-rw-r--r--target-arm/helper.h1
-rw-r--r--target-arm/op_helper.c9
-rw-r--r--target-arm/translate-a64.c2
-rw-r--r--target-arm/translate.c6
-rw-r--r--target-arm/translate.h2
-rw-r--r--target-i386/cc_helper.c2
-rw-r--r--target-i386/cpu.h5
-rw-r--r--target-i386/fpu_helper.c15
-rw-r--r--target-i386/gdbstub.c2
-rw-r--r--target-i386/translate.c48
-rw-r--r--target-ppc/STATUS9
-rw-r--r--target-ppc/cpu-models.c2
-rw-r--r--target-ppc/cpu-models.h1
-rw-r--r--target-ppc/cpu-qom.h2
-rw-r--r--target-ppc/cpu.h55
-rw-r--r--target-ppc/fpu_helper.c1294
-rw-r--r--target-ppc/helper.h207
-rw-r--r--target-ppc/int_helper.c1411
-rw-r--r--target-ppc/kvm.c117
-rw-r--r--target-ppc/kvm_ppc.h35
-rw-r--r--target-ppc/machine.c11
-rw-r--r--target-ppc/misc_helper.c4
-rw-r--r--target-ppc/mmu-hash64.c117
-rw-r--r--target-ppc/mmu-hash64.h47
-rw-r--r--target-ppc/mmu_helper.c3
-rw-r--r--target-ppc/translate.c1268
-rw-r--r--target-ppc/translate_init.c274
-rw-r--r--target-s390x/cpu.c15
-rw-r--r--target-s390x/cpu.h7
-rw-r--r--target-s390x/ioinst.h2
-rw-r--r--target-s390x/kvm.c257
-rw-r--r--target-s390x/misc_helper.c2
-rw-r--r--tcg/aarch64/tcg-target.c284
-rw-r--r--tcg/tcg.c2
-rw-r--r--tests/acpi-test-data/pc/DSDTbin4582 -> 4485 bytes
-rw-r--r--tests/acpi-test-data/pc/SSDTbin2200 -> 2275 bytes
-rw-r--r--tests/acpi-test-data/q35/DSDTbin7438 -> 7383 bytes
-rw-r--r--tests/acpi-test-data/q35/SSDTbin475 -> 564 bytes
-rw-r--r--tests/acpi-test.c42
-rw-r--r--tests/qapi-schema/qapi-schema-test.json24
-rw-r--r--tests/qapi-schema/qapi-schema-test.out19
-rwxr-xr-xtests/qemu-iotests-quick.sh1
-rwxr-xr-xtests/qemu-iotests/0519
-rw-r--r--tests/qemu-iotests/051.out15
-rwxr-xr-xtests/qemu-iotests/0813
-rw-r--r--tests/qemu-iotests/081.out2
-rwxr-xr-xtests/qemu-iotests/085192
-rw-r--r--tests/qemu-iotests/085.out55
-rwxr-xr-xtests/qemu-iotests/08665
-rw-r--r--tests/qemu-iotests/086.out18
-rwxr-xr-xtests/qemu-iotests/087122
-rw-r--r--tests/qemu-iotests/087.out40
-rw-r--r--tests/qemu-iotests/common.rc2
-rw-r--r--tests/qemu-iotests/group37
-rw-r--r--tests/test-int128.c15
-rw-r--r--tests/test-qmp-commands.c78
-rw-r--r--tests/test-qmp-input-strict.c69
-rw-r--r--tests/test-qmp-input-visitor.c45
-rw-r--r--tests/test-qmp-output-visitor.c67
-rw-r--r--tests/test-visitor-serialization.c14
-rw-r--r--thread-pool.c2
-rw-r--r--trace-events23
-rw-r--r--ui/Makefile.objs6
-rw-r--r--ui/cocoa.m81
-rw-r--r--ui/console.c69
-rw-r--r--ui/curses.c47
-rw-r--r--ui/gtk.c77
-rw-r--r--ui/input-legacy.c467
-rw-r--r--ui/input.c682
-rw-r--r--ui/sdl.c128
-rw-r--r--ui/sdl2-keymap.h266
-rw-r--r--ui/sdl2.c829
-rw-r--r--ui/sdl_keysym.h3
-rw-r--r--ui/spice-display.c37
-rw-r--r--ui/spice-input.c84
-rw-r--r--ui/vnc-enc-tight.c2
-rw-r--r--ui/vnc-jobs.c8
-rw-r--r--ui/vnc.c298
-rw-r--r--ui/vnc.h11
-rw-r--r--util/compatfd.c3
-rw-r--r--util/host-utils.c75
-rw-r--r--util/iov.c9
-rw-r--r--util/module.c2
-rw-r--r--util/qemu-thread-posix.c16
-rw-r--r--util/qemu-thread-win32.c10
-rw-r--r--vl.c105
-rw-r--r--xen-all.c2
-rw-r--r--xen-stub.c2
290 files changed, 14774 insertions, 2953 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 026ea4f021..7d17f83868 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -158,7 +158,6 @@ Guest CPU Cores (KVM):
----------------------
Overall
-M: Gleb Natapov <gleb@redhat.com>
M: Paolo Bonzini <pbonzini@redhat.com>
L: kvm@vger.kernel.org
S: Supported
@@ -176,12 +175,14 @@ S: Maintained
F: target-ppc/kvm.c
S390
+M: Christian Borntraeger <borntraeger@de.ibm.com>
+M: Cornelia Huck <cornelia.huck@de.ibm.com>
M: Alexander Graf <agraf@suse.de>
S: Maintained
F: target-s390x/kvm.c
+F: hw/intc/s390_flic.[hc]
X86
-M: Gleb Natapov <gleb@redhat.com>
M: Marcelo Tosatti <mtosatti@redhat.com>
L: kvm@vger.kernel.org
S: Supported
@@ -495,10 +496,13 @@ F: hw/s390x/s390-*.c
S390 Virtio-ccw
M: Cornelia Huck <cornelia.huck@de.ibm.com>
+M: Christian Borntraeger <borntraeger@de.ibm.com>
M: Alexander Graf <agraf@suse.de>
S: Supported
F: hw/s390x/s390-virtio-ccw.c
F: hw/s390x/css.[hc]
+F: hw/s390x/sclp*.[hc]
+F: hw/s390x/ipl*.[hc]
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
UniCore32 Machines
@@ -629,6 +633,7 @@ F: hw/block/virtio-blk.c
virtio-ccw
M: Cornelia Huck <cornelia.huck@de.ibm.com>
+M: Christian Borntraeger <borntraeger@de.ibm.com>
S: Supported
F: hw/s390x/virtio-ccw.[hc]
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
@@ -726,7 +731,7 @@ F: vl.c
Human Monitor (HMP)
M: Luiz Capitulino <lcapitulino@redhat.com>
-S: Supported
+S: Maintained
F: monitor.c
F: hmp.c
F: hmp-commands.hx
@@ -758,7 +763,7 @@ T: git git://github.com/bonzini/qemu.git nbd-next
QAPI
M: Luiz Capitulino <lcapitulino@redhat.com>
M: Michael Roth <mdroth@linux.vnet.ibm.com>
-S: Supported
+S: Maintained
F: qapi/
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
@@ -772,7 +777,7 @@ T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
QMP
M: Luiz Capitulino <lcapitulino@redhat.com>
-S: Supported
+S: Maintained
F: qmp.c
F: monitor.c
F: qmp-commands.hx
diff --git a/Makefile b/Makefile
index a28a3c8d49..bd9cd4fceb 100644
--- a/Makefile
+++ b/Makefile
@@ -159,6 +159,7 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
+$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
subdir-%:
@@ -319,7 +320,7 @@ ifdef INSTALL_BLOBS
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
acpi-dsdt.aml q35-acpi-dsdt.aml \
-ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \
+ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
@@ -398,7 +399,7 @@ endif
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
done
for d in $(TARGET_DIRS); do \
- $(MAKE) -C $$d $@ || exit 1 ; \
+ $(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \
done
# various test targets
diff --git a/Makefile.objs b/Makefile.objs
index 4a62913a4d..5cd3d816ff 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -21,11 +21,6 @@ block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o
block-obj-m = block/
-ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
-# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
-# only pull in the actual virtio-9p device if we also enabled virtio.
-CONFIG_REALLY_VIRTFS=y
-endif
######################################################################
# smartcard
diff --git a/arch_init.c b/arch_init.c
index fe1727922c..60c975db2b 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -164,8 +164,9 @@ static struct {
uint8_t *encoded_buf;
/* buffer for storing page content */
uint8_t *current_buf;
- /* Cache for XBZRLE */
+ /* Cache for XBZRLE, Protected by lock. */
PageCache *cache;
+ QemuMutex lock;
} XBZRLE = {
.encoded_buf = NULL,
.current_buf = NULL,
@@ -174,16 +175,52 @@ static struct {
/* buffer used for XBZRLE decoding */
static uint8_t *xbzrle_decoded_buf;
+static void XBZRLE_cache_lock(void)
+{
+ if (migrate_use_xbzrle())
+ qemu_mutex_lock(&XBZRLE.lock);
+}
+
+static void XBZRLE_cache_unlock(void)
+{
+ if (migrate_use_xbzrle())
+ qemu_mutex_unlock(&XBZRLE.lock);
+}
+
int64_t xbzrle_cache_resize(int64_t new_size)
{
+ PageCache *new_cache, *cache_to_free;
+
if (new_size < TARGET_PAGE_SIZE) {
return -1;
}
+ /* no need to lock, the current thread holds qemu big lock */
if (XBZRLE.cache != NULL) {
- return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) *
- TARGET_PAGE_SIZE;
+ /* check XBZRLE.cache again later */
+ if (pow2floor(new_size) == migrate_xbzrle_cache_size()) {
+ return pow2floor(new_size);
+ }
+ new_cache = cache_init(new_size / TARGET_PAGE_SIZE,
+ TARGET_PAGE_SIZE);
+ if (!new_cache) {
+ DPRINTF("Error creating cache\n");
+ return -1;
+ }
+
+ XBZRLE_cache_lock();
+ /* the XBZRLE.cache may have be destroyed, check it again */
+ if (XBZRLE.cache != NULL) {
+ cache_to_free = XBZRLE.cache;
+ XBZRLE.cache = new_cache;
+ } else {
+ cache_to_free = new_cache;
+ }
+ XBZRLE_cache_unlock();
+
+ cache_fini(cache_to_free);
}
+
return pow2floor(new_size);
}
@@ -539,6 +576,8 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
ret = ram_control_save_page(f, block->offset,
offset, TARGET_PAGE_SIZE, &bytes_sent);
+ XBZRLE_cache_lock();
+
current_addr = block->offset + offset;
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
if (ret != RAM_SAVE_CONTROL_DELAYED) {
@@ -587,6 +626,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
acct_info.norm_pages++;
}
+ XBZRLE_cache_unlock();
/* if page is unmodified, continue to the next */
if (bytes_sent > 0) {
last_sent_block = block;
@@ -654,6 +694,7 @@ static void migration_end(void)
migration_bitmap = NULL;
}
+ XBZRLE_cache_lock();
if (XBZRLE.cache) {
cache_fini(XBZRLE.cache);
g_free(XBZRLE.cache);
@@ -663,6 +704,7 @@ static void migration_end(void)
XBZRLE.encoded_buf = NULL;
XBZRLE.current_buf = NULL;
}
+ XBZRLE_cache_unlock();
}
static void ram_migration_cancel(void *opaque)
@@ -693,13 +735,17 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
dirty_rate_high_cnt = 0;
if (migrate_use_xbzrle()) {
+ qemu_mutex_lock_iothread();
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
TARGET_PAGE_SIZE,
TARGET_PAGE_SIZE);
if (!XBZRLE.cache) {
+ qemu_mutex_unlock_iothread();
DPRINTF("Error creating cache\n");
return -1;
}
+ qemu_mutex_init(&XBZRLE.lock);
+ qemu_mutex_unlock_iothread();
/* We prefer not to abort if there is no memory */
XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
diff --git a/backends/baum.c b/backends/baum.c
index 1132899026..665107fa9c 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -566,7 +566,7 @@ CharDriverState *chr_baum_init(void)
BaumDriverState *baum;
CharDriverState *chr;
brlapi_handle_t *handle;
-#ifdef CONFIG_SDL
+#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
SDL_SysWMinfo info;
#endif
int tty;
@@ -595,7 +595,7 @@ CharDriverState *chr_baum_init(void)
goto fail;
}
-#ifdef CONFIG_SDL
+#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
memset(&info, 0, sizeof(info));
SDL_VERSION(&info.version);
if (SDL_GetWMInfo(&info))
diff --git a/block.c b/block.c
index 2fd5482572..f1ef4b0109 100644
--- a/block.c
+++ b/block.c
@@ -547,8 +547,9 @@ int get_tmp_filename(char *filename, int size)
int fd;
const char *tmpdir;
tmpdir = getenv("TMPDIR");
- if (!tmpdir)
- tmpdir = "/tmp";
+ if (!tmpdir) {
+ tmpdir = "/var/tmp";
+ }
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
return -EOVERFLOW;
}
@@ -934,7 +935,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
bdrv_refresh_limits(bs);
assert(bdrv_opt_mem_align(bs) != 0);
- assert(bs->request_alignment != 0);
+ assert((bs->request_alignment != 0) || bs->sg);
#ifndef _WIN32
if (bs->is_temporary) {
@@ -1016,7 +1017,12 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
ret = -EINVAL;
goto fail;
}
- qdict_del(*options, "filename");
+
+ if (!drv->bdrv_needs_filename) {
+ qdict_del(*options, "filename");
+ } else {
+ filename = qdict_get_str(*options, "filename");
+ }
}
if (!drv->bdrv_file_open) {
@@ -1228,6 +1234,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
ret = bdrv_file_open(bs, filename, &options, flags & ~BDRV_O_PROTOCOL,
&local_err);
if (!ret) {
+ drv = bs->drv;
goto done;
} else if (bs->drv) {
goto close_and_fail;
@@ -1846,11 +1853,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
bs_src->device_name);
bs_dest->device_list = bs_src->device_list;
-
- /* keep the same entry in graph_bdrv_states
- * We do want to swap name but don't want to swap linked list entries
- */
- bs_dest->node_list = bs_src->node_list;
}
/*
@@ -1869,6 +1871,17 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
{
BlockDriverState tmp;
+ /* The code needs to swap the node_name but simply swapping node_list won't
+ * work so first remove the nodes from the graph list, do the swap then
+ * insert them back if needed.
+ */
+ if (bs_new->node_name[0] != '\0') {
+ QTAILQ_REMOVE(&graph_bdrv_states, bs_new, node_list);
+ }
+ if (bs_old->node_name[0] != '\0') {
+ QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list);
+ }
+
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
assert(bs_new->device_name[0] == '\0');
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
@@ -1897,6 +1910,14 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
assert(bs_new->io_limits_enabled == false);
assert(!throttle_have_timer(&bs_new->throttle_state));
+ /* insert the nodes back into the graph node list if needed */
+ if (bs_new->node_name[0] != '\0') {
+ QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_new, node_list);
+ }
+ if (bs_old->node_name[0] != '\0') {
+ QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list);
+ }
+
bdrv_rebind(bs_new);
bdrv_rebind(bs_old);
}
diff --git a/block/gluster.c b/block/gluster.c
index 14d390b4c7..a44d612923 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -3,21 +3,12 @@
*
* Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com>
*
- * Pipe handling mechanism in AIO implementation is derived from
- * block/rbd.c. Hence,
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
*
- * Copyright (C) 2010-2011 Christian Brunner <chb@muc.de>,
- * Josh Durgin <josh.durgin@dreamhost.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
*/
#include <glusterfs/api/glfs.h>
#include "block/block_int.h"
-#include "qemu/sockets.h"
#include "qemu/uri.h"
typedef struct GlusterAIOCB {
@@ -32,9 +23,6 @@ typedef struct BDRVGlusterState {
struct glfs_fd *fd;
} BDRVGlusterState;
-#define GLUSTER_FD_READ 0
-#define GLUSTER_FD_WRITE 1
-
typedef struct GlusterConf {
char *server;
int port;
@@ -45,11 +33,13 @@ typedef struct GlusterConf {
static void qemu_gluster_gconf_free(GlusterConf *gconf)
{
- g_free(gconf->server);
- g_free(gconf->volname);
- g_free(gconf->image);
- g_free(gconf->transport);
- g_free(gconf);
+ if (gconf) {
+ g_free(gconf->server);
+ g_free(gconf->volname);
+ g_free(gconf->image);
+ g_free(gconf->transport);
+ g_free(gconf);
+ }
}
static int parse_volume_options(GlusterConf *gconf, char *path)
@@ -272,11 +262,28 @@ static QemuOptsList runtime_opts = {
},
};
+static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
+{
+ assert(open_flags != NULL);
+
+ *open_flags |= O_BINARY;
+
+ if (bdrv_flags & BDRV_O_RDWR) {
+ *open_flags |= O_RDWR;
+ } else {
+ *open_flags |= O_RDONLY;
+ }
+
+ if ((bdrv_flags & BDRV_O_NOCACHE)) {
+ *open_flags |= O_DIRECT;
+ }
+}
+
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
int bdrv_flags, Error **errp)
{
BDRVGlusterState *s = bs->opaque;
- int open_flags = O_BINARY;
+ int open_flags = 0;
int ret = 0;
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
QemuOpts *opts;
@@ -299,15 +306,7 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
goto out;
}
- if (bdrv_flags & BDRV_O_RDWR) {
- open_flags |= O_RDWR;
- } else {
- open_flags |= O_RDONLY;
- }
-
- if ((bdrv_flags & BDRV_O_NOCACHE)) {
- open_flags |= O_DIRECT;
- }
+ qemu_gluster_parse_flags(bdrv_flags, &open_flags);
s->fd = glfs_open(s->glfs, gconf->image, open_flags);
if (!s->fd) {
@@ -329,6 +328,96 @@ out:
return ret;
}
+typedef struct BDRVGlusterReopenState {
+ struct glfs *glfs;
+ struct glfs_fd *fd;
+} BDRVGlusterReopenState;
+
+
+static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
+ BlockReopenQueue *queue, Error **errp)
+{
+ int ret = 0;
+ BDRVGlusterReopenState *reop_s;
+ GlusterConf *gconf = NULL;
+ int open_flags = 0;
+
+ assert(state != NULL);
+ assert(state->bs != NULL);
+
+ state->opaque = g_malloc0(sizeof(BDRVGlusterReopenState));
+ reop_s = state->opaque;
+
+ qemu_gluster_parse_flags(state->flags, &open_flags);
+
+ gconf = g_malloc0(sizeof(GlusterConf));
+
+ reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, errp);
+ if (reop_s->glfs == NULL) {
+ ret = -errno;
+ goto exit;
+ }
+
+ reop_s->fd = glfs_open(reop_s->glfs, gconf->image, open_flags);
+ if (reop_s->fd == NULL) {
+ /* reops->glfs will be cleaned up in _abort */
+ ret = -errno;
+ goto exit;
+ }
+
+exit:
+ /* state->opaque will be freed in either the _abort or _commit */
+ qemu_gluster_gconf_free(gconf);
+ return ret;
+}
+
+static void qemu_gluster_reopen_commit(BDRVReopenState *state)
+{
+ BDRVGlusterReopenState *reop_s = state->opaque;
+ BDRVGlusterState *s = state->bs->opaque;
+
+
+ /* close the old */
+ if (s->fd) {
+ glfs_close(s->fd);
+ }
+ if (s->glfs) {
+ glfs_fini(s->glfs);
+ }
+
+ /* use the newly opened image / connection */
+ s->fd = reop_s->fd;
+ s->glfs = reop_s->glfs;
+
+ g_free(state->opaque);
+ state->opaque = NULL;
+
+ return;
+}
+
+
+static void qemu_gluster_reopen_abort(BDRVReopenState *state)
+{
+ BDRVGlusterReopenState *reop_s = state->opaque;
+
+ if (reop_s == NULL) {
+ return;
+ }
+
+ if (reop_s->fd) {
+ glfs_close(reop_s->fd);
+ }
+
+ if (reop_s->glfs) {
+ glfs_fini(reop_s->glfs);
+ }
+
+ g_free(state->opaque);
+ state->opaque = NULL;
+
+ return;
+}
+
#ifdef CONFIG_GLUSTERFS_ZEROFILL
static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
@@ -619,6 +708,9 @@ static BlockDriver bdrv_gluster = {
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
+ .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
+ .bdrv_reopen_commit = qemu_gluster_reopen_commit,
+ .bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
@@ -643,6 +735,9 @@ static BlockDriver bdrv_gluster_tcp = {
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
+ .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
+ .bdrv_reopen_commit = qemu_gluster_reopen_commit,
+ .bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
@@ -667,6 +762,9 @@ static BlockDriver bdrv_gluster_unix = {
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
+ .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
+ .bdrv_reopen_commit = qemu_gluster_reopen_commit,
+ .bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
@@ -691,6 +789,9 @@ static BlockDriver bdrv_gluster_rdma = {
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
+ .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
+ .bdrv_reopen_commit = qemu_gluster_reopen_commit,
+ .bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
diff --git a/block/iscsi.c b/block/iscsi.c
index 41ec09709d..b490e98c05 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -145,12 +145,13 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
if (iTask->retries-- > 0 && status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
+ error_report("iSCSI CheckCondition: %s", iscsi_get_error(iscsi));
iTask->do_retry = 1;
goto out;
}
if (status != SCSI_STATUS_GOOD) {
- error_report("iSCSI: Failure. %s", iscsi_get_error(iscsi));
+ error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
}
out:
@@ -325,6 +326,7 @@ retry:
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
@@ -399,6 +401,7 @@ retry:
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
@@ -433,6 +436,7 @@ retry:
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
@@ -683,6 +687,7 @@ retry:
scsi_free_scsi_task(iTask.task);
iTask.task = NULL;
}
+ iTask.complete = 0;
goto retry;
}
@@ -767,6 +772,7 @@ retry:
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
@@ -830,24 +836,26 @@ retry:
qemu_coroutine_yield();
}
+ if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
+ iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
+ iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
+ /* WRITE SAME is not supported by the target */
+ iscsilun->has_write_same = false;
+ scsi_free_scsi_task(iTask.task);
+ return -ENOTSUP;
+ }
+
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
iTask.task = NULL;
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
if (iTask.status != SCSI_STATUS_GOOD) {
- if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
- iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
- iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
- /* WRITE SAME is not supported by the target */
- iscsilun->has_write_same = false;
- return -ENOTSUP;
- }
-
return -EIO;
}
@@ -1060,7 +1068,7 @@ static QemuOptsList runtime_opts = {
};
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
- int evpd, int pc, Error **errp)
+ int evpd, int pc, void **inq, Error **errp)
{
int full_size;
struct scsi_task *task = NULL;
@@ -1079,14 +1087,19 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
}
}
+ *inq = scsi_datain_unmarshall(task);
+ if (*inq == NULL) {
+ error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
+ goto fail;
+ }
+
return task;
fail:
error_setg(errp, "iSCSI: Inquiry command failed : %s",
iscsi_get_error(iscsi));
- if (task) {
+ if (task != NULL) {
scsi_free_scsi_task(task);
- return NULL;
}
return NULL;
}
@@ -1107,11 +1120,12 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
struct iscsi_url *iscsi_url = NULL;
struct scsi_task *task = NULL;
struct scsi_inquiry_standard *inq = NULL;
+ struct scsi_inquiry_supported_pages *inq_vpd;
char *initiator_name = NULL;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
- int ret;
+ int i, ret;
if ((BDRV_SECTOR_SIZE % 512) != 0) {
error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
@@ -1197,24 +1211,17 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
iscsilun->iscsi = iscsi;
iscsilun->lun = iscsi_url->lun;
+ iscsilun->has_write_same = true;
- task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
-
- if (task == NULL || task->status != SCSI_STATUS_GOOD) {
- error_setg(errp, "iSCSI: failed to send inquiry command.");
- ret = -EINVAL;
- goto out;
- }
-
- inq = scsi_datain_unmarshall(task);
- if (inq == NULL) {
- error_setg(errp, "iSCSI: Failed to unmarshall inquiry data.");
+ task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 0, 0,
+ (void **) &inq, errp);
+ if (task == NULL) {
ret = -EINVAL;
goto out;
}
-
iscsilun->type = inq->periperal_device_type;
- iscsilun->has_write_same = true;
+ scsi_free_scsi_task(task);
+ task = NULL;
iscsi_readcapacity_sync(iscsilun, &local_err);
if (local_err != NULL) {
@@ -1224,55 +1231,56 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
bs->request_alignment = iscsilun->block_size;
- /* 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
- * to read from the device to guess the image format.
+ /* We don't have any emulation for devices other than disks and CD-ROMs, so
+ * this must be sg ioctl compatible. We force it to be sg, otherwise qemu
+ * will try to read from the device to guess the image format.
*/
- if (iscsilun->type == TYPE_MEDIUM_CHANGER ||
- iscsilun->type == TYPE_TAPE) {
+ if (iscsilun->type != TYPE_DISK && iscsilun->type != TYPE_ROM) {
bs->sg = 1;
}
- if (iscsilun->lbpme) {
- struct scsi_inquiry_logical_block_provisioning *inq_lbp;
- task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
- SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
- errp);
- if (task == NULL) {
- ret = -EINVAL;
- goto out;
- }
- inq_lbp = scsi_datain_unmarshall(task);
- if (inq_lbp == NULL) {
- error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
- ret = -EINVAL;
- goto out;
- }
- memcpy(&iscsilun->lbp, inq_lbp,
- sizeof(struct scsi_inquiry_logical_block_provisioning));
- scsi_free_scsi_task(task);
- task = NULL;
+ task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
+ SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES,
+ (void **) &inq_vpd, errp);
+ if (task == NULL) {
+ ret = -EINVAL;
+ goto out;
}
-
- if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
+ for (i = 0; i < inq_vpd->num_pages; i++) {
+ struct scsi_task *inq_task;
+ struct scsi_inquiry_logical_block_provisioning *inq_lbp;
struct scsi_inquiry_block_limits *inq_bl;
- task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
- SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, errp);
- if (task == NULL) {
- ret = -EINVAL;
- goto out;
- }
- inq_bl = scsi_datain_unmarshall(task);
- if (inq_bl == NULL) {
- error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
- ret = -EINVAL;
- goto out;
+ switch (inq_vpd->pages[i]) {
+ case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
+ inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
+ SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
+ (void **) &inq_lbp, errp);
+ if (inq_task == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
+ memcpy(&iscsilun->lbp, inq_lbp,
+ sizeof(struct scsi_inquiry_logical_block_provisioning));
+ scsi_free_scsi_task(inq_task);
+ break;
+ case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
+ inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
+ SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS,
+ (void **) &inq_bl, errp);
+ if (inq_task == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
+ memcpy(&iscsilun->bl, inq_bl,
+ sizeof(struct scsi_inquiry_block_limits));
+ scsi_free_scsi_task(inq_task);
+ break;
+ default:
+ break;
}
- memcpy(&iscsilun->bl, inq_bl,
- sizeof(struct scsi_inquiry_block_limits));
- scsi_free_scsi_task(task);
- task = NULL;
}
+ scsi_free_scsi_task(task);
+ task = NULL;
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
/* Set up a timer for sending out iSCSI NOPs */
diff --git a/block/mirror.c b/block/mirror.c
index e683959570..dd5ee056b4 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -520,9 +520,6 @@ static void mirror_complete(BlockJob *job, Error **errp)
ret = bdrv_open_backing_file(s->target, NULL, &local_err);
if (ret < 0) {
- char backing_filename[PATH_MAX];
- bdrv_get_full_backing_filename(s->target, backing_filename,
- sizeof(backing_filename));
error_propagate(errp, local_err);
return;
}
diff --git a/block/quorum.c b/block/quorum.c
index 6c28239718..bd997b7322 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -200,11 +200,14 @@ static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret)
{
QObject *data;
assert(node_name);
- data = qobject_from_jsonf("{ 'ret': %d"
- ", 'node-name': %s"
+ data = qobject_from_jsonf("{ 'node-name': %s"
", 'sector-num': %" PRId64
", 'sectors-count': %d }",
- ret, node_name, acb->sector_num, acb->nb_sectors);
+ node_name, acb->sector_num, acb->nb_sectors);
+ if (ret < 0) {
+ QDict *dict = qobject_to_qdict(data);
+ qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
+ }
monitor_protocol_event(QEVENT_QUORUM_REPORT_BAD, data);
qobject_decref(data);
}
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 161ea14812..e6b4c1fe02 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -336,6 +336,17 @@ error:
}
#endif
+static void raw_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ /* The filename does not have to be prefixed by the protocol name, since
+ * "file" is the default protocol; therefore, the return value of this
+ * function call can be ignored. */
+ strstart(filename, "file:", &filename);
+
+ qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
static QemuOptsList raw_runtime_opts = {
.name = "raw",
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
@@ -1230,6 +1241,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
int result = 0;
int64_t total_size = 0;
+ strstart(filename, "file:", &filename);
+
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
@@ -1412,6 +1425,7 @@ static BlockDriver bdrv_file = {
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
.bdrv_probe = NULL, /* no probe for protocols */
+ .bdrv_parse_filename = raw_parse_filename,
.bdrv_file_open = raw_open,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
diff --git a/block/raw-win32.c b/block/raw-win32.c
index ae1c8e6cca..99547488e4 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -251,6 +251,17 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
}
}
+static void raw_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ /* The filename does not have to be prefixed by the protocol name, since
+ * "file" is the default protocol; therefore, the return value of this
+ * function call can be ignored. */
+ strstart(filename, "file:", &filename);
+
+ qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
static QemuOptsList raw_runtime_opts = {
.name = "raw",
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
@@ -470,6 +481,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
int fd;
int64_t total_size = 0;
+ strstart(filename, "file:", &filename);
+
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
@@ -504,6 +517,7 @@ static BlockDriver bdrv_file = {
.protocol_name = "file",
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
+ .bdrv_parse_filename = raw_parse_filename,
.bdrv_file_open = raw_open,
.bdrv_close = raw_close,
.bdrv_create = raw_create,
diff --git a/block/vmdk.c b/block/vmdk.c
index 83839f9b7a..b69988d169 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1184,7 +1184,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
break;
case VMDK_OK:
ret = BDRV_BLOCK_DATA;
- if (extent->file == bs->file) {
+ if (extent->file == bs->file && !extent->compressed) {
ret |= BDRV_BLOCK_OFFSET_VALID | offset;
}
diff --git a/blockdev.c b/blockdev.c
index 357f7607ff..c3422a1d41 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2266,6 +2266,7 @@ void qmp_block_job_complete(const char *device, Error **errp)
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
{
QmpOutputVisitor *ov = qmp_output_visitor_new();
+ DriveInfo *dinfo;
QObject *obj;
QDict *qdict;
Error *local_err = NULL;
@@ -2282,8 +2283,10 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
*
* For now, simply forbidding the combination for all drivers will do. */
if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
- bool direct = options->cache->has_direct && options->cache->direct;
- if (!options->has_cache && !direct) {
+ bool direct = options->has_cache &&
+ options->cache->has_direct &&
+ options->cache->direct;
+ if (!direct) {
error_setg(errp, "aio=native requires cache.direct=true");
goto fail;
}
@@ -2301,12 +2304,18 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
qdict_flatten(qdict);
- blockdev_init(NULL, qdict, &local_err);
+ dinfo = blockdev_init(NULL, qdict, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto fail;
}
+ if (bdrv_key_required(dinfo->bdrv)) {
+ drive_uninit(dinfo);
+ error_setg(errp, "blockdev-add doesn't support encrypted devices");
+ goto fail;
+ }
+
fail:
qmp_output_visitor_cleanup(ov);
}
diff --git a/configure b/configure
index 8ad03ea17d..95399798d0 100755
--- a/configure
+++ b/configure
@@ -14,13 +14,14 @@ fi
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}"
TMPO="${TMPDIR1}/${TMPB}.o"
+TMPCXX="${TMPDIR1}/${TMPB}.cxx"
TMPL="${TMPDIR1}/${TMPB}.lo"
TMPA="${TMPDIR1}/lib${TMPB}.la"
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
# NB: do not call "exit" in the trap handler; this is buggy with some shells;
# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org>
-trap "rm -f $TMPC $TMPO $TMPE" EXIT INT QUIT TERM
+trap "rm -f $TMPC $TMPO $TMPCXX $TMPE" EXIT INT QUIT TERM
rm -f config.log
# Print a helpful header at the top of config.log
@@ -54,10 +55,13 @@ error_exit() {
exit 1
}
-do_cc() {
- # Run the compiler, capturing its output to the log.
- echo $cc "$@" >> config.log
- $cc "$@" >> config.log 2>&1 || return $?
+do_compiler() {
+ # Run the compiler, capturing its output to the log. First argument
+ # is compiler binary to execute.
+ local compiler="$1"
+ shift
+ echo $compiler "$@" >> config.log
+ $compiler "$@" >> config.log 2>&1 || return $?
# Test passed. If this is an --enable-werror build, rerun
# the test with -Werror and bail out if it fails. This
# makes warning-generating-errors in configure test code
@@ -71,14 +75,39 @@ do_cc() {
return 0
;;
esac
- echo $cc -Werror "$@" >> config.log
- $cc -Werror "$@" >> config.log 2>&1 && return $?
+ echo $compiler -Werror "$@" >> config.log
+ $compiler -Werror "$@" >> config.log 2>&1 && return $?
error_exit "configure test passed without -Werror but failed with -Werror." \
"This is probably a bug in the configure script. The failing command" \
"will be at the bottom of config.log." \
"You can run configure with --disable-werror to bypass this check."
}
+do_cc() {
+ do_compiler "$cc" "$@"
+}
+
+do_cxx() {
+ do_compiler "$cxx" "$@"
+}
+
+update_cxxflags() {
+ # Set QEMU_CXXFLAGS from QEMU_CFLAGS by filtering out those
+ # options which some versions of GCC's C++ compiler complain about
+ # because they only make sense for C programs.
+ QEMU_CXXFLAGS=
+ for arg in $QEMU_CFLAGS; do
+ case $arg in
+ -Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\
+ -Wold-style-declaration|-Wold-style-definition|-Wredundant-decls)
+ ;;
+ *)
+ QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }$arg
+ ;;
+ esac
+ done
+}
+
compile_object() {
do_cc $QEMU_CFLAGS -c -o $TMPO $TMPC
}
@@ -207,6 +236,7 @@ fdt=""
netmap="no"
pixman=""
sdl=""
+sdlabi="1.2"
virtfs=""
vnc="yes"
sparse="no"
@@ -283,6 +313,8 @@ libusb=""
usb_redir=""
glx=""
zlib="yes"
+lzo="no"
+snappy="no"
guest_agent=""
guest_agent_with_vss="no"
vss_win32_sdk=""
@@ -364,12 +396,13 @@ query_pkg_config() {
}
pkg_config=query_pkg_config
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
+sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
# If the user hasn't specified ARFLAGS, default to 'rv', just as make does.
ARFLAGS="${ARFLAGS-rv}"
# default flags for all hosts
-QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
+QEMU_CFLAGS="-fno-strict-aliasing -fno-common $QEMU_CFLAGS"
QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
@@ -773,6 +806,8 @@ for opt do
;;
--enable-sdl) sdl="yes"
;;
+ --with-sdlabi=*) sdlabi="$optarg"
+ ;;
--disable-qom-cast-debug) qom_cast_debug="no"
;;
--enable-qom-cast-debug) qom_cast_debug="yes"
@@ -995,6 +1030,10 @@ for opt do
;;
--disable-zlib-test) zlib="no"
;;
+ --enable-lzo) lzo="yes"
+ ;;
+ --enable-snappy) snappy="yes"
+ ;;
--enable-guest-agent) guest_agent="yes"
;;
--disable-guest-agent) guest_agent="no"
@@ -1190,6 +1229,7 @@ Advanced options (experts only):
--disable-werror disable compilation abort on warning
--disable-sdl disable SDL
--enable-sdl enable SDL
+ --with-sdlabi select preferred SDL ABI 1.2 or 2.0
--disable-gtk disable gtk UI
--enable-gtk enable gtk UI
--disable-virtfs disable VirtFS
@@ -1289,6 +1329,8 @@ Advanced options (experts only):
--enable-libusb enable libusb (for usb passthrough)
--disable-usb-redir disable usb network redirection support
--enable-usb-redir enable usb network redirection support
+ --enable-lzo enable the support of lzo compression library
+ --enable-snappy enable the support of snappy compression library
--disable-guest-agent disable building of the QEMU Guest Agent
--enable-guest-agent enable building of the QEMU Guest Agent
--with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent
@@ -1327,6 +1369,19 @@ if test "$ARCH" = "unknown"; then
fi
fi
+# Consult white-list to determine whether to enable werror
+# by default. Only enable by default for git builds
+z_version=`cut -f3 -d. $source_path/VERSION`
+
+if test -z "$werror" ; then
+ if test -d "$source_path/.git" -a \
+ "$linux" = "yes" ; then
+ werror="yes"
+ else
+ werror="no"
+ fi
+fi
+
# check that the C compiler works.
cat > $TMPC <<EOF
int main(void) { return 0; }
@@ -1347,14 +1402,16 @@ EOF
compile_object
- cat > $TMPC <<EOF
+ cat > $TMPCXX <<EOF
extern "C" {
int c_function(void);
}
int c_function(void) { return 42; }
EOF
- if (cc=$cxx do_cc $QEMU_CFLAGS -o $TMPE $TMPC $TMPO $LDFLAGS); then
+ update_cxxflags
+
+ if do_cxx $QEMU_CXXFLAGS -o $TMPE $TMPCXX $TMPO $LDFLAGS; then
# C++ compiler $cxx works ok with C compiler $cc
:
else
@@ -1367,19 +1424,6 @@ else
cxx=
fi
-# Consult white-list to determine whether to enable werror
-# by default. Only enable by default for git builds
-z_version=`cut -f3 -d. $source_path/VERSION`
-
-if test -z "$werror" ; then
- if test -d "$source_path/.git" -a \
- "$linux" = "yes" ; then
- werror="yes"
- else
- werror="no"
- fi
-fi
-
gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
@@ -1660,6 +1704,42 @@ fi
LIBS="$LIBS -lz"
##########################################
+# lzo check
+
+if test "$lzo" != "no" ; then
+ cat > $TMPC << EOF
+#include <lzo/lzo1x.h>
+int main(void) { lzo_version(); return 0; }
+EOF
+ if compile_prog "" "-llzo2" ; then
+ :
+ else
+ error_exit "lzo check failed" \
+ "Make sure to have the lzo libs and headers installed."
+ fi
+
+ libs_softmmu="$libs_softmmu -llzo2"
+fi
+
+##########################################
+# snappy check
+
+if test "$snappy" != "no" ; then
+ cat > $TMPC << EOF
+#include <snappy-c.h>
+int main(void) { snappy_max_compressed_length(4096); return 0; }
+EOF
+ if compile_prog "" "-lsnappy" ; then
+ :
+ else
+ error_exit "snappy check failed" \
+ "Make sure to have the snappy libs and headers installed."
+ fi
+
+ libs_softmmu="$libs_softmmu -lsnappy"
+fi
+
+##########################################
# libseccomp check
if test "$seccomp" != "no" ; then
@@ -1911,12 +1991,22 @@ fi
# Look for sdl configuration program (pkg-config or sdl-config). Try
# sdl-config even without cross prefix, and favour pkg-config over sdl-config.
-if test "`basename $sdl_config`" != sdl-config && ! has ${sdl_config}; then
- sdl_config=sdl-config
+
+if test $sdlabi = "2.0"; then
+ sdl_config=$sdl2_config
+ sdlname=sdl2
+ sdlconfigname=sdl2_config
+else
+ sdlname=sdl
+ sdlconfigname=sdl_config
fi
-if $pkg_config sdl --exists; then
- sdlconfig="$pkg_config sdl"
+if test "`basename $sdl_config`" != $sdlconfigname && ! has ${sdl_config}; then
+ sdl_config=$sdlconfigname
+fi
+
+if $pkg_config $sdlname --exists; then
+ sdlconfig="$pkg_config $sdlname"
_sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
elif has ${sdl_config}; then
sdlconfig="$sdl_config"
@@ -4017,7 +4107,11 @@ echo "vhost-net support $vhost_net"
echo "vhost-scsi support $vhost_scsi"
echo "Trace backend $trace_backend"
echo "Trace output file $trace_file-<pid>"
+if test "$spice" = "yes"; then
echo "spice support $spice ($spice_protocol_version/$spice_server_version)"
+else
+echo "spice support $spice"
+fi
echo "rbd support $rbd"
echo "xfsctl support $xfs"
echo "nss used $smartcard_nss"
@@ -4045,6 +4139,8 @@ echo "TPM passthrough $tpm_passthrough"
echo "QOM debugging $qom_cast_debug"
echo "vhdx $vhdx"
echo "Quorum $quorum"
+echo "lzo support $lzo"
+echo "snappy support $snappy"
if test "$sdl_too_old" = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -4368,6 +4464,14 @@ if test "$glx" = "yes" ; then
echo "GLX_LIBS=$glx_libs" >> $config_host_mak
fi
+if test "$lzo" = "yes" ; then
+ echo "CONFIG_LZO=y" >> $config_host_mak
+fi
+
+if test "$snappy" = "yes" ; then
+ echo "CONFIG_SNAPPY=y" >> $config_host_mak
+fi
+
if test "$libiscsi" = "yes" ; then
echo "CONFIG_LIBISCSI=m" >> $config_host_mak
if test "$libiscsi_version" = "1.4.0"; then
@@ -4868,6 +4972,12 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
echo "CONFIG_ALPHA_DIS=y" >> $config_target_mak
echo "CONFIG_ALPHA_DIS=y" >> config-all-disas.mak
;;
+ aarch64)
+ if test -n "${cxx}"; then
+ echo "CONFIG_ARM_A64_DIS=y" >> $config_target_mak
+ echo "CONFIG_ARM_A64_DIS=y" >> config-all-disas.mak
+ fi
+ ;;
arm)
echo "CONFIG_ARM_DIS=y" >> $config_target_mak
echo "CONFIG_ARM_DIS=y" >> config-all-disas.mak
diff --git a/cpus.c b/cpus.c
index 945d85b326..b6421fd2a8 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1117,8 +1117,13 @@ void resume_all_vcpus(void)
}
}
+/* For temporary buffers for forming a name */
+#define VCPU_THREAD_NAME_SIZE 16
+
static void qemu_tcg_init_vcpu(CPUState *cpu)
{
+ char thread_name[VCPU_THREAD_NAME_SIZE];
+
tcg_cpu_address_space_init(cpu, cpu->as);
/* share a single thread for all cpus with TCG */
@@ -1127,8 +1132,10 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
qemu_cond_init(cpu->halt_cond);
tcg_halt_cond = cpu->halt_cond;
- qemu_thread_create(cpu->thread, qemu_tcg_cpu_thread_fn, cpu,
- QEMU_THREAD_JOINABLE);
+ snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG",
+ cpu->cpu_index);
+ qemu_thread_create(cpu->thread, thread_name, qemu_tcg_cpu_thread_fn,
+ cpu, QEMU_THREAD_JOINABLE);
#ifdef _WIN32
cpu->hThread = qemu_thread_get_handle(cpu->thread);
#endif
@@ -1144,11 +1151,15 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)
static void qemu_kvm_start_vcpu(CPUState *cpu)
{
+ char thread_name[VCPU_THREAD_NAME_SIZE];
+
cpu->thread = g_malloc0(sizeof(QemuThread));
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
qemu_cond_init(cpu->halt_cond);
- qemu_thread_create(cpu->thread, qemu_kvm_cpu_thread_fn, cpu,
- QEMU_THREAD_JOINABLE);
+ snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/KVM",
+ cpu->cpu_index);
+ qemu_thread_create(cpu->thread, thread_name, qemu_kvm_cpu_thread_fn,
+ cpu, QEMU_THREAD_JOINABLE);
while (!cpu->created) {
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
}
@@ -1156,10 +1167,14 @@ static void qemu_kvm_start_vcpu(CPUState *cpu)
static void qemu_dummy_start_vcpu(CPUState *cpu)
{
+ char thread_name[VCPU_THREAD_NAME_SIZE];
+
cpu->thread = g_malloc0(sizeof(QemuThread));
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
qemu_cond_init(cpu->halt_cond);
- qemu_thread_create(cpu->thread, qemu_dummy_cpu_thread_fn, cpu,
+ snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/DUMMY",
+ cpu->cpu_index);
+ qemu_thread_create(cpu->thread, thread_name, qemu_dummy_cpu_thread_fn, cpu,
QEMU_THREAD_JOINABLE);
while (!cpu->created) {
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index e5f9d36913..07c51ced1f 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -47,4 +47,5 @@ CONFIG_E500=y
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
# For PReP
CONFIG_MC146818RTC=y
+CONFIG_ETSEC=y
CONFIG_ISA_TESTDEV=y
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index 81fbc68654..d843dc0d57 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -1,2 +1,3 @@
CONFIG_VIRTIO=y
CONFIG_SCLPCONSOLE=y
+CONFIG_S390_FLIC=$(CONFIG_KVM)
diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak
index 8fc93dd643..ab796b3d4f 100644
--- a/default-configs/sparc-softmmu.mak
+++ b/default-configs/sparc-softmmu.mak
@@ -10,6 +10,7 @@ CONFIG_EMPTY_SLOT=y
CONFIG_PCNET_COMMON=y
CONFIG_LANCE=y
CONFIG_TCX=y
+CONFIG_CG3=y
CONFIG_SLAVIO=y
CONFIG_CS4231=y
CONFIG_GRLIB=y
diff --git a/disas/libvixl/a64/disasm-a64.cc b/disas/libvixl/a64/disasm-a64.cc
index 5c6b898ea6..5f172da7d3 100644
--- a/disas/libvixl/a64/disasm-a64.cc
+++ b/disas/libvixl/a64/disasm-a64.cc
@@ -1342,7 +1342,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
ASSERT(format[5] == 'L');
AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
if (instr->ShiftMoveWide() > 0) {
- AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
+ AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide());
}
}
return 8;
@@ -1391,7 +1391,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
}
case 'F': { // IFPSingle, IFPDouble or IFPFBits.
if (format[3] == 'F') { // IFPFbits.
- AppendToOutput("#%d", 64 - instr->FPScale());
+ AppendToOutput("#%" PRId64, 64 - instr->FPScale());
return 8;
} else {
AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
@@ -1412,23 +1412,23 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
return 5;
}
case 'P': { // IP - Conditional compare.
- AppendToOutput("#%d", instr->ImmCondCmp());
+ AppendToOutput("#%" PRId64, instr->ImmCondCmp());
return 2;
}
case 'B': { // Bitfields.
return SubstituteBitfieldImmediateField(instr, format);
}
case 'E': { // IExtract.
- AppendToOutput("#%d", instr->ImmS());
+ AppendToOutput("#%" PRId64, instr->ImmS());
return 8;
}
case 'S': { // IS - Test and branch bit.
- AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
- instr->ImmTestBranchBit40());
+ AppendToOutput("#%" PRId64, (instr->ImmTestBranchBit5() << 5) |
+ instr->ImmTestBranchBit40());
return 2;
}
case 'D': { // IDebug - HLT and BRK instructions.
- AppendToOutput("#0x%x", instr->ImmException());
+ AppendToOutput("#0x%" PRIx64, instr->ImmException());
return 6;
}
default: {
@@ -1598,12 +1598,12 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
(((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
(instr->ExtendMode() == UXTX))) {
if (instr->ImmExtendShift() > 0) {
- AppendToOutput(", lsl #%d", instr->ImmExtendShift());
+ AppendToOutput(", lsl #%" PRId64, instr->ImmExtendShift());
}
} else {
AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
if (instr->ImmExtendShift() > 0) {
- AppendToOutput(" #%d", instr->ImmExtendShift());
+ AppendToOutput(" #%" PRId64, instr->ImmExtendShift());
}
}
return 3;
@@ -1632,7 +1632,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
if (!((ext == UXTX) && (shift == 0))) {
AppendToOutput(", %s", extend_mode[ext]);
if (shift != 0) {
- AppendToOutput(" #%d", instr->SizeLS());
+ AppendToOutput(" #%" PRId64, instr->SizeLS());
}
}
return 9;
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
index 00f95154dd..145402e078 100644
--- a/docs/qmp/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -225,6 +225,45 @@ Data:
"timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
}
+QUORUM_FAILURE
+--------------
+
+Emitted by the Quorum block driver if it fails to establish a quorum.
+
+Data:
+
+- "reference": device name if defined else node name.
+- "sector-num": Number of the first sector of the failed read operation.
+- "sector-count": Failed read operation sector count.
+
+Example:
+
+{ "event": "QUORUM_FAILURE",
+ "data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
+ "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+
+QUORUM_REPORT_BAD
+-----------------
+
+Emitted to report a corruption of a Quorum file.
+
+Data:
+
+- "error": Error message (json-string, optional)
+ Only present on failure. This field contains a human-readable
+ error message. There are no semantics other than that the
+ block layer reported an error and clients should not try to
+ interpret the error string.
+- "node-name": The graph node name of the block driver state.
+- "sector-num": Number of the first sector of the failed read operation.
+- "sector-count": Failed read operation sector count.
+
+Example:
+
+{ "event": "QUORUM_REPORT_BAD",
+ "data": { "node-name": "1.raw", "sector-num": 345435, "sector-count": 5 },
+ "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+
RESET
-----
@@ -500,39 +539,3 @@ Example:
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events.
-
-QUORUM_FAILURE
---------------
-
-Emitted by the Quorum block driver if it fails to establish a quorum.
-
-Data:
-
-- "reference": device name if defined else node name.
-- "sector-num": Number of the first sector of the failed read operation.
-- "sector-count": Failed read operation sector count.
-
-Example:
-
-{ "event": "QUORUM_FAILURE",
- "data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
- "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-QUORUM_REPORT_BAD
------------------
-
-Emitted to report a corruption of a Quorum file.
-
-Data:
-
-- "ret": The IO return code.
-- "node-name": The graph node name of the block driver state.
-- "sector-num": Number of the first sector of the failed read operation.
-- "sector-count": Failed read operation sector count.
-
-Example:
-
-{ "event": "QUORUM_REPORT_BAD",
- "data": { "ret": 0, "node-name": "1.raw", "sector-num": 345435,
- "sector-count": 5 },
- "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
diff --git a/dump.c b/dump.c
index 80a9116c77..14b3d1d6ae 100644
--- a/dump.c
+++ b/dump.c
@@ -25,6 +25,17 @@
#include "qapi/error.h"
#include "qmp-commands.h"
+#include <zlib.h>
+#ifdef CONFIG_LZO
+#include <lzo/lzo1x.h>
+#endif
+#ifdef CONFIG_SNAPPY
+#include <snappy-c.h>
+#endif
+#ifndef ELF_MACHINE_UNAME
+#define ELF_MACHINE_UNAME "Unknown"
+#endif
+
static uint16_t cpu_convert_to_target16(uint16_t val, int endian)
{
if (endian == ELFDATA2LSB) {
@@ -76,6 +87,19 @@ typedef struct DumpState {
int64_t begin;
int64_t length;
Error **errp;
+
+ uint8_t *note_buf; /* buffer for notes */
+ size_t note_buf_offset; /* the writing place in note_buf */
+ uint32_t nr_cpus; /* number of guest's cpu */
+ size_t page_size; /* guest's page size */
+ uint32_t page_shift; /* guest's page shift */
+ uint64_t max_mapnr; /* the biggest guest's phys-mem's number */
+ size_t len_dump_bitmap; /* the size of the place used to store
+ dump_bitmap in vmcore */
+ off_t offset_dump_bitmap; /* offset of dump_bitmap part in vmcore */
+ off_t offset_page; /* offset of page part in vmcore */
+ size_t num_dumpable; /* number of page that can be dumped */
+ uint32_t flag_compress; /* indicate the compression format */
} DumpState;
static int dump_cleanup(DumpState *s)
@@ -99,7 +123,7 @@ static void dump_error(DumpState *s, const char *reason)
dump_cleanup(s);
}
-static int fd_write_vmcore(void *buf, size_t size, void *opaque)
+static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
{
DumpState *s = opaque;
size_t written_size;
@@ -271,7 +295,7 @@ static inline int cpu_index(CPUState *cpu)
return cpu->cpu_index + 1;
}
-static int write_elf64_notes(DumpState *s)
+static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s)
{
CPUState *cpu;
int ret;
@@ -279,7 +303,7 @@ static int write_elf64_notes(DumpState *s)
CPU_FOREACH(cpu) {
id = cpu_index(cpu);
- ret = cpu_write_elf64_note(fd_write_vmcore, cpu, id, s);
+ ret = cpu_write_elf64_note(f, cpu, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes.\n");
return -1;
@@ -287,7 +311,7 @@ static int write_elf64_notes(DumpState *s)
}
CPU_FOREACH(cpu) {
- ret = cpu_write_elf64_qemunote(fd_write_vmcore, cpu, s);
+ ret = cpu_write_elf64_qemunote(f, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status.\n");
return -1;
@@ -321,7 +345,7 @@ static int write_elf32_note(DumpState *s)
return 0;
}
-static int write_elf32_notes(DumpState *s)
+static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s)
{
CPUState *cpu;
int ret;
@@ -329,7 +353,7 @@ static int write_elf32_notes(DumpState *s)
CPU_FOREACH(cpu) {
id = cpu_index(cpu);
- ret = cpu_write_elf32_note(fd_write_vmcore, cpu, id, s);
+ ret = cpu_write_elf32_note(f, cpu, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes.\n");
return -1;
@@ -337,7 +361,7 @@ static int write_elf32_notes(DumpState *s)
}
CPU_FOREACH(cpu) {
- ret = cpu_write_elf32_qemunote(fd_write_vmcore, cpu, s);
+ ret = cpu_write_elf32_qemunote(f, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status.\n");
return -1;
@@ -574,7 +598,7 @@ static int dump_begin(DumpState *s)
}
/* write notes to vmcore */
- if (write_elf64_notes(s) < 0) {
+ if (write_elf64_notes(fd_write_vmcore, s) < 0) {
return -1;
}
@@ -597,7 +621,7 @@ static int dump_begin(DumpState *s)
}
/* write notes to vmcore */
- if (write_elf32_notes(s) < 0) {
+ if (write_elf32_notes(fd_write_vmcore, s) < 0) {
return -1;
}
}
@@ -686,6 +710,800 @@ static int create_vmcore(DumpState *s)
return 0;
}
+static int write_start_flat_header(int fd)
+{
+ uint8_t *buf;
+ MakedumpfileHeader mh;
+ int ret = 0;
+
+ memset(&mh, 0, sizeof(mh));
+ strncpy(mh.signature, MAKEDUMPFILE_SIGNATURE,
+ strlen(MAKEDUMPFILE_SIGNATURE));
+
+ mh.type = cpu_to_be64(TYPE_FLAT_HEADER);
+ mh.version = cpu_to_be64(VERSION_FLAT_HEADER);
+
+ buf = g_malloc0(MAX_SIZE_MDF_HEADER);
+ memcpy(buf, &mh, sizeof(mh));
+
+ size_t written_size;
+ written_size = qemu_write_full(fd, buf, MAX_SIZE_MDF_HEADER);
+ if (written_size != MAX_SIZE_MDF_HEADER) {
+ ret = -1;
+ }
+
+ g_free(buf);
+ return ret;
+}
+
+static int write_end_flat_header(int fd)
+{
+ MakedumpfileDataHeader mdh;
+
+ mdh.offset = END_FLAG_FLAT_HEADER;
+ mdh.buf_size = END_FLAG_FLAT_HEADER;
+
+ size_t written_size;
+ written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
+ if (written_size != sizeof(mdh)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_buffer(int fd, off_t offset, const void *buf, size_t size)
+{
+ size_t written_size;
+ MakedumpfileDataHeader mdh;
+
+ mdh.offset = cpu_to_be64(offset);
+ mdh.buf_size = cpu_to_be64(size);
+
+ written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
+ if (written_size != sizeof(mdh)) {
+ return -1;
+ }
+
+ written_size = qemu_write_full(fd, buf, size);
+ if (written_size != size) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int buf_write_note(const void *buf, size_t size, void *opaque)
+{
+ DumpState *s = opaque;
+
+ /* note_buf is not enough */
+ if (s->note_buf_offset + size > s->note_size) {
+ return -1;
+ }
+
+ memcpy(s->note_buf + s->note_buf_offset, buf, size);
+
+ s->note_buf_offset += size;
+
+ return 0;
+}
+
+/* write common header, sub header and elf note to vmcore */
+static int create_header32(DumpState *s)
+{
+ int ret = 0;
+ DiskDumpHeader32 *dh = NULL;
+ KdumpSubHeader32 *kh = NULL;
+ size_t size;
+ int endian = s->dump_info.d_endian;
+ uint32_t block_size;
+ uint32_t sub_hdr_size;
+ uint32_t bitmap_blocks;
+ uint32_t status = 0;
+ uint64_t offset_note;
+
+ /* write common header, the version of kdump-compressed format is 6th */
+ size = sizeof(DiskDumpHeader32);
+ dh = g_malloc0(size);
+
+ strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
+ dh->header_version = cpu_convert_to_target32(6, endian);
+ block_size = s->page_size;
+ dh->block_size = cpu_convert_to_target32(block_size, endian);
+ sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size;
+ sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
+ dh->sub_hdr_size = cpu_convert_to_target32(sub_hdr_size, endian);
+ /* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
+ dh->max_mapnr = cpu_convert_to_target32(MIN(s->max_mapnr, UINT_MAX),
+ endian);
+ dh->nr_cpus = cpu_convert_to_target32(s->nr_cpus, endian);
+ bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
+ dh->bitmap_blocks = cpu_convert_to_target32(bitmap_blocks, endian);
+ strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
+
+ if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
+ status |= DUMP_DH_COMPRESSED_ZLIB;
+ }
+#ifdef CONFIG_LZO
+ if (s->flag_compress & DUMP_DH_COMPRESSED_LZO) {
+ status |= DUMP_DH_COMPRESSED_LZO;
+ }
+#endif
+#ifdef CONFIG_SNAPPY
+ if (s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) {
+ status |= DUMP_DH_COMPRESSED_SNAPPY;
+ }
+#endif
+ dh->status = cpu_convert_to_target32(status, endian);
+
+ if (write_buffer(s->fd, 0, dh, size) < 0) {
+ dump_error(s, "dump: failed to write disk dump header.\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* write sub header */
+ size = sizeof(KdumpSubHeader32);
+ kh = g_malloc0(size);
+
+ /* 64bit max_mapnr_64 */
+ kh->max_mapnr_64 = cpu_convert_to_target64(s->max_mapnr, endian);
+ kh->phys_base = cpu_convert_to_target32(PHYS_BASE, endian);
+ kh->dump_level = cpu_convert_to_target32(DUMP_LEVEL, endian);
+
+ offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
+ kh->offset_note = cpu_convert_to_target64(offset_note, endian);
+ kh->note_size = cpu_convert_to_target32(s->note_size, endian);
+
+ if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
+ block_size, kh, size) < 0) {
+ dump_error(s, "dump: failed to write kdump sub header.\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* write note */
+ s->note_buf = g_malloc0(s->note_size);
+ s->note_buf_offset = 0;
+
+ /* use s->note_buf to store notes temporarily */
+ if (write_elf32_notes(buf_write_note, s) < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ if (write_buffer(s->fd, offset_note, s->note_buf,
+ s->note_size) < 0) {
+ dump_error(s, "dump: failed to write notes");
+ ret = -1;
+ goto out;
+ }
+
+ /* get offset of dump_bitmap */
+ s->offset_dump_bitmap = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size) *
+ block_size;
+
+ /* get offset of page */
+ s->offset_page = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size + bitmap_blocks) *
+ block_size;
+
+out:
+ g_free(dh);
+ g_free(kh);
+ g_free(s->note_buf);
+
+ return ret;
+}
+
+/* write common header, sub header and elf note to vmcore */
+static int create_header64(DumpState *s)
+{
+ int ret = 0;
+ DiskDumpHeader64 *dh = NULL;
+ KdumpSubHeader64 *kh = NULL;
+ size_t size;
+ int endian = s->dump_info.d_endian;
+ uint32_t block_size;
+ uint32_t sub_hdr_size;
+ uint32_t bitmap_blocks;
+ uint32_t status = 0;
+ uint64_t offset_note;
+
+ /* write common header, the version of kdump-compressed format is 6th */
+ size = sizeof(DiskDumpHeader64);
+ dh = g_malloc0(size);
+
+ strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
+ dh->header_version = cpu_convert_to_target32(6, endian);
+ block_size = s->page_size;
+ dh->block_size = cpu_convert_to_target32(block_size, endian);
+ sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size;
+ sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
+ dh->sub_hdr_size = cpu_convert_to_target32(sub_hdr_size, endian);
+ /* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
+ dh->max_mapnr = cpu_convert_to_target32(MIN(s->max_mapnr, UINT_MAX),
+ endian);
+ dh->nr_cpus = cpu_convert_to_target32(s->nr_cpus, endian);
+ bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
+ dh->bitmap_blocks = cpu_convert_to_target32(bitmap_blocks, endian);
+ strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
+
+ if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
+ status |= DUMP_DH_COMPRESSED_ZLIB;
+ }
+#ifdef CONFIG_LZO
+ if (s->flag_compress & DUMP_DH_COMPRESSED_LZO) {
+ status |= DUMP_DH_COMPRESSED_LZO;
+ }
+#endif
+#ifdef CONFIG_SNAPPY
+ if (s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) {
+ status |= DUMP_DH_COMPRESSED_SNAPPY;
+ }
+#endif
+ dh->status = cpu_convert_to_target32(status, endian);
+
+ if (write_buffer(s->fd, 0, dh, size) < 0) {
+ dump_error(s, "dump: failed to write disk dump header.\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* write sub header */
+ size = sizeof(KdumpSubHeader64);
+ kh = g_malloc0(size);
+
+ /* 64bit max_mapnr_64 */
+ kh->max_mapnr_64 = cpu_convert_to_target64(s->max_mapnr, endian);
+ kh->phys_base = cpu_convert_to_target64(PHYS_BASE, endian);
+ kh->dump_level = cpu_convert_to_target32(DUMP_LEVEL, endian);
+
+ offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
+ kh->offset_note = cpu_convert_to_target64(offset_note, endian);
+ kh->note_size = cpu_convert_to_target64(s->note_size, endian);
+
+ if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
+ block_size, kh, size) < 0) {
+ dump_error(s, "dump: failed to write kdump sub header.\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* write note */
+ s->note_buf = g_malloc0(s->note_size);
+ s->note_buf_offset = 0;
+
+ /* use s->note_buf to store notes temporarily */
+ if (write_elf64_notes(buf_write_note, s) < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ if (write_buffer(s->fd, offset_note, s->note_buf,
+ s->note_size) < 0) {
+ dump_error(s, "dump: failed to write notes");
+ ret = -1;
+ goto out;
+ }
+
+ /* get offset of dump_bitmap */
+ s->offset_dump_bitmap = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size) *
+ block_size;
+
+ /* get offset of page */
+ s->offset_page = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size + bitmap_blocks) *
+ block_size;
+
+out:
+ g_free(dh);
+ g_free(kh);
+ g_free(s->note_buf);
+
+ return ret;
+}
+
+static int write_dump_header(DumpState *s)
+{
+ if (s->dump_info.d_machine == EM_386) {
+ return create_header32(s);
+ } else {
+ return create_header64(s);
+ }
+}
+
+/*
+ * set dump_bitmap sequencely. the bit before last_pfn is not allowed to be
+ * rewritten, so if need to set the first bit, set last_pfn and pfn to 0.
+ * set_dump_bitmap will always leave the recently set bit un-sync. And setting
+ * (last bit + sizeof(buf) * 8) to 0 will do flushing the content in buf into
+ * vmcore, ie. synchronizing un-sync bit into vmcore.
+ */
+static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
+ uint8_t *buf, DumpState *s)
+{
+ off_t old_offset, new_offset;
+ off_t offset_bitmap1, offset_bitmap2;
+ uint32_t byte, bit;
+
+ /* should not set the previous place */
+ assert(last_pfn <= pfn);
+
+ /*
+ * if the bit needed to be set is not cached in buf, flush the data in buf
+ * to vmcore firstly.
+ * making new_offset be bigger than old_offset can also sync remained data
+ * into vmcore.
+ */
+ old_offset = BUFSIZE_BITMAP * (last_pfn / PFN_BUFBITMAP);
+ new_offset = BUFSIZE_BITMAP * (pfn / PFN_BUFBITMAP);
+
+ while (old_offset < new_offset) {
+ /* calculate the offset and write dump_bitmap */
+ offset_bitmap1 = s->offset_dump_bitmap + old_offset;
+ if (write_buffer(s->fd, offset_bitmap1, buf,
+ BUFSIZE_BITMAP) < 0) {
+ return -1;
+ }
+
+ /* dump level 1 is chosen, so 1st and 2nd bitmap are same */
+ offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap +
+ old_offset;
+ if (write_buffer(s->fd, offset_bitmap2, buf,
+ BUFSIZE_BITMAP) < 0) {
+ return -1;
+ }
+
+ memset(buf, 0, BUFSIZE_BITMAP);
+ old_offset += BUFSIZE_BITMAP;
+ }
+
+ /* get the exact place of the bit in the buf, and set it */
+ byte = (pfn % PFN_BUFBITMAP) / CHAR_BIT;
+ bit = (pfn % PFN_BUFBITMAP) % CHAR_BIT;
+ if (value) {
+ buf[byte] |= 1u << bit;
+ } else {
+ buf[byte] &= ~(1u << bit);
+ }
+
+ return 0;
+}
+
+/*
+ * exam every page and return the page frame number and the address of the page.
+ * bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys
+ * blocks, so block->target_start and block->target_end should be interal
+ * multiples of the target page size.
+ */
+static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
+ uint8_t **bufptr, DumpState *s)
+{
+ GuestPhysBlock *block = *blockptr;
+ hwaddr addr;
+ uint8_t *buf;
+
+ /* block == NULL means the start of the iteration */
+ if (!block) {
+ block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
+ *blockptr = block;
+ assert(block->target_start % s->page_size == 0);
+ assert(block->target_end % s->page_size == 0);
+ *pfnptr = paddr_to_pfn(block->target_start, s->page_shift);
+ if (bufptr) {
+ *bufptr = block->host_addr;
+ }
+ return true;
+ }
+
+ *pfnptr = *pfnptr + 1;
+ addr = pfn_to_paddr(*pfnptr, s->page_shift);
+
+ if ((addr >= block->target_start) &&
+ (addr + s->page_size <= block->target_end)) {
+ buf = block->host_addr + (addr - block->target_start);
+ } else {
+ /* the next page is in the next block */
+ block = QTAILQ_NEXT(block, next);
+ *blockptr = block;
+ if (!block) {
+ return false;
+ }
+ assert(block->target_start % s->page_size == 0);
+ assert(block->target_end % s->page_size == 0);
+ *pfnptr = paddr_to_pfn(block->target_start, s->page_shift);
+ buf = block->host_addr;
+ }
+
+ if (bufptr) {
+ *bufptr = buf;
+ }
+
+ return true;
+}
+
+static int write_dump_bitmap(DumpState *s)
+{
+ int ret = 0;
+ uint64_t last_pfn, pfn;
+ void *dump_bitmap_buf;
+ size_t num_dumpable;
+ GuestPhysBlock *block_iter = NULL;
+
+ /* dump_bitmap_buf is used to store dump_bitmap temporarily */
+ dump_bitmap_buf = g_malloc0(BUFSIZE_BITMAP);
+
+ num_dumpable = 0;
+ last_pfn = 0;
+
+ /*
+ * exam memory page by page, and set the bit in dump_bitmap corresponded
+ * to the existing page.
+ */
+ while (get_next_page(&block_iter, &pfn, NULL, s)) {
+ ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to set dump_bitmap.\n");
+ ret = -1;
+ goto out;
+ }
+
+ last_pfn = pfn;
+ num_dumpable++;
+ }
+
+ /*
+ * set_dump_bitmap will always leave the recently set bit un-sync. Here we
+ * set last_pfn + PFN_BUFBITMAP to 0 and those set but un-sync bit will be
+ * synchronized into vmcore.
+ */
+ if (num_dumpable > 0) {
+ ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false,
+ dump_bitmap_buf, s);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to sync dump_bitmap.\n");
+ ret = -1;
+ goto out;
+ }
+ }
+
+ /* number of dumpable pages that will be dumped later */
+ s->num_dumpable = num_dumpable;
+
+out:
+ g_free(dump_bitmap_buf);
+
+ return ret;
+}
+
+static void prepare_data_cache(DataCache *data_cache, DumpState *s,
+ off_t offset)
+{
+ data_cache->fd = s->fd;
+ data_cache->data_size = 0;
+ data_cache->buf_size = BUFSIZE_DATA_CACHE;
+ data_cache->buf = g_malloc0(BUFSIZE_DATA_CACHE);
+ data_cache->offset = offset;
+}
+
+static int write_cache(DataCache *dc, const void *buf, size_t size,
+ bool flag_sync)
+{
+ /*
+ * dc->buf_size should not be less than size, otherwise dc will never be
+ * enough
+ */
+ assert(size <= dc->buf_size);
+
+ /*
+ * if flag_sync is set, synchronize data in dc->buf into vmcore.
+ * otherwise check if the space is enough for caching data in buf, if not,
+ * write the data in dc->buf to dc->fd and reset dc->buf
+ */
+ if ((!flag_sync && dc->data_size + size > dc->buf_size) ||
+ (flag_sync && dc->data_size > 0)) {
+ if (write_buffer(dc->fd, dc->offset, dc->buf, dc->data_size) < 0) {
+ return -1;
+ }
+
+ dc->offset += dc->data_size;
+ dc->data_size = 0;
+ }
+
+ if (!flag_sync) {
+ memcpy(dc->buf + dc->data_size, buf, size);
+ dc->data_size += size;
+ }
+
+ return 0;
+}
+
+static void free_data_cache(DataCache *data_cache)
+{
+ g_free(data_cache->buf);
+}
+
+static size_t get_len_buf_out(size_t page_size, uint32_t flag_compress)
+{
+ size_t len_buf_out_zlib, len_buf_out_lzo, len_buf_out_snappy;
+ size_t len_buf_out;
+
+ /* init buf_out */
+ len_buf_out_zlib = len_buf_out_lzo = len_buf_out_snappy = 0;
+
+ /* buf size for zlib */
+ len_buf_out_zlib = compressBound(page_size);
+
+ /* buf size for lzo */
+#ifdef CONFIG_LZO
+ if (flag_compress & DUMP_DH_COMPRESSED_LZO) {
+ if (lzo_init() != LZO_E_OK) {
+ /* return 0 to indicate lzo is unavailable */
+ return 0;
+ }
+ }
+
+ /*
+ * LZO will expand incompressible data by a little amount. please check the
+ * following URL to see the expansion calculation:
+ * http://www.oberhumer.com/opensource/lzo/lzofaq.php
+ */
+ len_buf_out_lzo = page_size + page_size / 16 + 64 + 3;
+#endif
+
+#ifdef CONFIG_SNAPPY
+ /* buf size for snappy */
+ len_buf_out_snappy = snappy_max_compressed_length(page_size);
+#endif
+
+ /* get the biggest that can store all kinds of compressed page */
+ len_buf_out = MAX(len_buf_out_zlib,
+ MAX(len_buf_out_lzo, len_buf_out_snappy));
+
+ return len_buf_out;
+}
+
+/*
+ * check if the page is all 0
+ */
+static inline bool is_zero_page(const uint8_t *buf, size_t page_size)
+{
+ return buffer_is_zero(buf, page_size);
+}
+
+static int write_dump_pages(DumpState *s)
+{
+ int ret = 0;
+ DataCache page_desc, page_data;
+ size_t len_buf_out, size_out;
+#ifdef CONFIG_LZO
+ lzo_bytep wrkmem = NULL;
+#endif
+ uint8_t *buf_out = NULL;
+ off_t offset_desc, offset_data;
+ PageDescriptor pd, pd_zero;
+ uint8_t *buf;
+ int endian = s->dump_info.d_endian;
+ GuestPhysBlock *block_iter = NULL;
+ uint64_t pfn_iter;
+
+ /* get offset of page_desc and page_data in dump file */
+ offset_desc = s->offset_page;
+ offset_data = offset_desc + sizeof(PageDescriptor) * s->num_dumpable;
+
+ prepare_data_cache(&page_desc, s, offset_desc);
+ prepare_data_cache(&page_data, s, offset_data);
+
+ /* prepare buffer to store compressed data */
+ len_buf_out = get_len_buf_out(s->page_size, s->flag_compress);
+ if (len_buf_out == 0) {
+ dump_error(s, "dump: failed to get length of output buffer.\n");
+ goto out;
+ }
+
+#ifdef CONFIG_LZO
+ wrkmem = g_malloc(LZO1X_1_MEM_COMPRESS);
+#endif
+
+ buf_out = g_malloc(len_buf_out);
+
+ /*
+ * init zero page's page_desc and page_data, because every zero page
+ * uses the same page_data
+ */
+ pd_zero.size = cpu_convert_to_target32(s->page_size, endian);
+ pd_zero.flags = cpu_convert_to_target32(0, endian);
+ pd_zero.offset = cpu_convert_to_target64(offset_data, endian);
+ pd_zero.page_flags = cpu_convert_to_target64(0, endian);
+ buf = g_malloc0(s->page_size);
+ ret = write_cache(&page_data, buf, s->page_size, false);
+ g_free(buf);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write page data(zero page).\n");
+ goto out;
+ }
+
+ offset_data += s->page_size;
+
+ /*
+ * dump memory to vmcore page by page. zero page will all be resided in the
+ * first page of page section
+ */
+ while (get_next_page(&block_iter, &pfn_iter, &buf, s)) {
+ /* check zero page */
+ if (is_zero_page(buf, s->page_size)) {
+ ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
+ false);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write page desc.\n");
+ goto out;
+ }
+ } else {
+ /*
+ * not zero page, then:
+ * 1. compress the page
+ * 2. write the compressed page into the cache of page_data
+ * 3. get page desc of the compressed page and write it into the
+ * cache of page_desc
+ *
+ * only one compression format will be used here, for
+ * s->flag_compress is set. But when compression fails to work,
+ * we fall back to save in plaintext.
+ */
+ size_out = len_buf_out;
+ if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) &&
+ (compress2(buf_out, (uLongf *)&size_out, buf, s->page_size,
+ Z_BEST_SPEED) == Z_OK) && (size_out < s->page_size)) {
+ pd.flags = cpu_convert_to_target32(DUMP_DH_COMPRESSED_ZLIB,
+ endian);
+ pd.size = cpu_convert_to_target32(size_out, endian);
+
+ ret = write_cache(&page_data, buf_out, size_out, false);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write page data.\n");
+ goto out;
+ }
+#ifdef CONFIG_LZO
+ } else if ((s->flag_compress & DUMP_DH_COMPRESSED_LZO) &&
+ (lzo1x_1_compress(buf, s->page_size, buf_out,
+ (lzo_uint *)&size_out, wrkmem) == LZO_E_OK) &&
+ (size_out < s->page_size)) {
+ pd.flags = cpu_convert_to_target32(DUMP_DH_COMPRESSED_LZO,
+ endian);
+ pd.size = cpu_convert_to_target32(size_out, endian);
+
+ ret = write_cache(&page_data, buf_out, size_out, false);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write page data.\n");
+ goto out;
+ }
+#endif
+#ifdef CONFIG_SNAPPY
+ } else if ((s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) &&
+ (snappy_compress((char *)buf, s->page_size,
+ (char *)buf_out, &size_out) == SNAPPY_OK) &&
+ (size_out < s->page_size)) {
+ pd.flags = cpu_convert_to_target32(
+ DUMP_DH_COMPRESSED_SNAPPY, endian);
+ pd.size = cpu_convert_to_target32(size_out, endian);
+
+ ret = write_cache(&page_data, buf_out, size_out, false);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write page data.\n");
+ goto out;
+ }
+#endif
+ } else {
+ /*
+ * fall back to save in plaintext, size_out should be
+ * assigned to s->page_size
+ */
+ pd.flags = cpu_convert_to_target32(0, endian);
+ size_out = s->page_size;
+ pd.size = cpu_convert_to_target32(size_out, endian);
+
+ ret = write_cache(&page_data, buf, s->page_size, false);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write page data.\n");
+ goto out;
+ }
+ }
+
+ /* get and write page desc here */
+ pd.page_flags = cpu_convert_to_target64(0, endian);
+ pd.offset = cpu_convert_to_target64(offset_data, endian);
+ offset_data += size_out;
+
+ ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write page desc.\n");
+ goto out;
+ }
+ }
+ }
+
+ ret = write_cache(&page_desc, NULL, 0, true);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to sync cache for page_desc.\n");
+ goto out;
+ }
+ ret = write_cache(&page_data, NULL, 0, true);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to sync cache for page_data.\n");
+ goto out;
+ }
+
+out:
+ free_data_cache(&page_desc);
+ free_data_cache(&page_data);
+
+#ifdef CONFIG_LZO
+ g_free(wrkmem);
+#endif
+
+ g_free(buf_out);
+
+ return ret;
+}
+
+static int create_kdump_vmcore(DumpState *s)
+{
+ int ret;
+
+ /*
+ * the kdump-compressed format is:
+ * File offset
+ * +------------------------------------------+ 0x0
+ * | main header (struct disk_dump_header) |
+ * |------------------------------------------+ block 1
+ * | sub header (struct kdump_sub_header) |
+ * |------------------------------------------+ block 2
+ * | 1st-dump_bitmap |
+ * |------------------------------------------+ block 2 + X blocks
+ * | 2nd-dump_bitmap | (aligned by block)
+ * |------------------------------------------+ block 2 + 2 * X blocks
+ * | page desc for pfn 0 (struct page_desc) | (aligned by block)
+ * | page desc for pfn 1 (struct page_desc) |
+ * | : |
+ * |------------------------------------------| (not aligned by block)
+ * | page data (pfn 0) |
+ * | page data (pfn 1) |
+ * | : |
+ * +------------------------------------------+
+ */
+
+ ret = write_start_flat_header(s->fd);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write start flat header.\n");
+ return -1;
+ }
+
+ ret = write_dump_header(s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ ret = write_dump_bitmap(s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ ret = write_dump_pages(s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ ret = write_end_flat_header(s->fd);
+ if (ret < 0) {
+ dump_error(s, "dump: failed to write end flat header.\n");
+ return -1;
+ }
+
+ dump_completed(s);
+
+ return 0;
+}
+
static ram_addr_t get_start_block(DumpState *s)
{
GuestPhysBlock *block;
@@ -714,7 +1532,16 @@ static ram_addr_t get_start_block(DumpState *s)
return -1;
}
-static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
+static void get_max_mapnr(DumpState *s)
+{
+ GuestPhysBlock *last_block;
+
+ last_block = QTAILQ_LAST(&s->guest_phys_blocks.head, GuestPhysBlockHead);
+ s->max_mapnr = paddr_to_pfn(last_block->target_end, s->page_shift);
+}
+
+static int dump_init(DumpState *s, int fd, bool has_format,
+ DumpGuestMemoryFormat format, bool paging, bool has_filter,
int64_t begin, int64_t length, Error **errp)
{
CPUState *cpu;
@@ -722,6 +1549,11 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
Error *err = NULL;
int ret;
+ /* kdump-compressed is conflict with paging and filter */
+ if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
+ assert(!paging && !has_filter);
+ }
+
if (runstate_is_running()) {
vm_stop(RUN_STATE_SAVE_VM);
s->resume = true;
@@ -782,6 +1614,38 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
qemu_get_guest_simple_memory_mapping(&s->list, &s->guest_phys_blocks);
}
+ s->nr_cpus = nr_cpus;
+ s->page_size = TARGET_PAGE_SIZE;
+ s->page_shift = ffs(s->page_size) - 1;
+
+ get_max_mapnr(s);
+
+ uint64_t tmp;
+ tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), s->page_size);
+ s->len_dump_bitmap = tmp * s->page_size;
+
+ /* init for kdump-compressed format */
+ if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
+ switch (format) {
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB:
+ s->flag_compress = DUMP_DH_COMPRESSED_ZLIB;
+ break;
+
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO:
+ s->flag_compress = DUMP_DH_COMPRESSED_LZO;
+ break;
+
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY:
+ s->flag_compress = DUMP_DH_COMPRESSED_SNAPPY;
+ break;
+
+ default:
+ s->flag_compress = 0;
+ }
+
+ return 0;
+ }
+
if (s->has_filter) {
memory_mapping_filter(&s->list, s->begin, s->length);
}
@@ -841,14 +1705,25 @@ cleanup:
}
void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
- int64_t begin, bool has_length, int64_t length,
- Error **errp)
+ int64_t begin, bool has_length,
+ int64_t length, bool has_format,
+ DumpGuestMemoryFormat format, Error **errp)
{
const char *p;
int fd = -1;
DumpState *s;
int ret;
+ /*
+ * kdump-compressed format need the whole memory dumped, so paging or
+ * filter is not supported here.
+ */
+ if ((has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) &&
+ (paging || has_begin || has_length)) {
+ error_setg(errp, "kdump-compressed format doesn't support paging or "
+ "filter");
+ return;
+ }
if (has_begin && !has_length) {
error_set(errp, QERR_MISSING_PARAMETER, "length");
return;
@@ -858,6 +1733,21 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
return;
}
+ /* check whether lzo/snappy is supported */
+#ifndef CONFIG_LZO
+ if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO) {
+ error_setg(errp, "kdump-lzo is not available now");
+ return;
+ }
+#endif
+
+#ifndef CONFIG_SNAPPY
+ if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY) {
+ error_setg(errp, "kdump-snappy is not available now");
+ return;
+ }
+#endif
+
#if !defined(WIN32)
if (strstart(file, "fd:", &p)) {
fd = monitor_get_fd(cur_mon, p, errp);
@@ -882,15 +1772,55 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
s = g_malloc0(sizeof(DumpState));
- ret = dump_init(s, fd, paging, has_begin, begin, length, errp);
+ ret = dump_init(s, fd, has_format, format, paging, has_begin,
+ begin, length, errp);
if (ret < 0) {
g_free(s);
return;
}
- if (create_vmcore(s) < 0 && !error_is_set(s->errp)) {
- error_set(errp, QERR_IO_ERROR);
+ if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
+ if (create_kdump_vmcore(s) < 0 && !error_is_set(s->errp)) {
+ error_set(errp, QERR_IO_ERROR);
+ }
+ } else {
+ if (create_vmcore(s) < 0 && !error_is_set(s->errp)) {
+ error_set(errp, QERR_IO_ERROR);
+ }
}
g_free(s);
}
+
+DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp)
+{
+ DumpGuestMemoryFormatList *item;
+ DumpGuestMemoryCapability *cap =
+ g_malloc0(sizeof(DumpGuestMemoryCapability));
+
+ /* elf is always available */
+ item = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ cap->formats = item;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_ELF;
+
+ /* kdump-zlib is always available */
+ item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ item = item->next;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
+
+ /* add new item if kdump-lzo is available */
+#ifdef CONFIG_LZO
+ item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ item = item->next;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
+#endif
+
+ /* add new item if kdump-snappy is available */
+#ifdef CONFIG_SNAPPY
+ item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ item = item->next;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
+#endif
+
+ return cap;
+}
diff --git a/exec.c b/exec.c
index f47b2b149e..31ed3750aa 100644
--- a/exec.c
+++ b/exec.c
@@ -17,9 +17,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
-#ifdef _WIN32
-#include <windows.h>
-#else
+#ifndef _WIN32
#include <sys/types.h>
#include <sys/mman.h>
#endif
diff --git a/fsdev/Makefile.objs b/fsdev/Makefile.objs
index 206289c49f..c27dad3f6d 100644
--- a/fsdev/Makefile.objs
+++ b/fsdev/Makefile.objs
@@ -1,4 +1,6 @@
-ifeq ($(CONFIG_REALLY_VIRTFS),y)
+ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
+# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
+# only pull in the actual virtio-9p device if we also enabled virtio.
common-obj-y = qemu-fsdev.o virtio-9p-marshal.o
else
common-obj-y = qemu-fsdev-dummy.o
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 713a7b2b87..bfecb8706c 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -595,7 +595,7 @@ static int do_readlink(struct iovec *iovec, struct iovec *out_iovec)
}
buffer = g_malloc(size);
v9fs_string_init(&target);
- retval = readlink(path.data, buffer, size);
+ retval = readlink(path.data, buffer, size - 1);
if (retval > 0) {
buffer[retval] = '\0';
v9fs_string_sprintf(&target, "%s", buffer);
diff --git a/hmp.c b/hmp.c
index e3ddd4654d..2f279c4ff2 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1311,8 +1311,11 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
const char *file = qdict_get_str(qdict, "filename");
bool has_begin = qdict_haskey(qdict, "begin");
bool has_length = qdict_haskey(qdict, "length");
+ /* kdump-compressed format is not supported for HMP */
+ bool has_format = false;
int64_t begin = 0;
int64_t length = 0;
+ enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
char *prot;
if (has_begin) {
@@ -1325,7 +1328,7 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
prot = g_strconcat("file:", file, NULL);
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
- &errp);
+ has_format, dump_format, &errp);
hmp_handle_error(mon, &errp);
g_free(prot);
}
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 3891050748..42ee614e27 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -17,35 +17,55 @@
#include "block/coroutine.h"
#include "virtio-9p-coth.h"
+static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
+{
+ ssize_t len, maxlen = PATH_MAX;
+
+ buf->data = g_malloc(PATH_MAX);
+ for(;;) {
+ len = s->ops->readlink(&s->ctx, path, buf->data, maxlen);
+ if (len < 0) {
+ g_free(buf->data);
+ buf->data = NULL;
+ buf->size = 0;
+ break;
+ } else if (len == maxlen) {
+ /*
+ * We dodn't have space to put the NULL or we have more
+ * to read. Increase the size and try again
+ */
+ maxlen *= 2;
+ g_free(buf->data);
+ buf->data = g_malloc(maxlen);
+ continue;
+ }
+ /*
+ * Null terminate the readlink output
+ */
+ buf->data[len] = '\0';
+ buf->size = len;
+ break;
+ }
+ return len;
+}
+
int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
{
int err;
- ssize_t len;
V9fsState *s = pdu->s;
if (v9fs_request_cancelled(pdu)) {
return -EINTR;
}
- buf->data = g_malloc(PATH_MAX);
v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- len = s->ops->readlink(&s->ctx, path,
- buf->data, PATH_MAX - 1);
- if (len > -1) {
- buf->size = len;
- buf->data[len] = 0;
- err = 0;
- } else {
+ err = __readlink(s, path, buf);
+ if (err < 0) {
err = -errno;
}
});
v9fs_path_unlock(s);
- if (err) {
- g_free(buf->data);
- buf->data = NULL;
- buf->size = 0;
- }
return err;
}
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index 17002a3d28..4b79cefd13 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -498,7 +498,7 @@ static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
const char *name, V9fsPath *target)
{
- char buffer[PATH_MAX];
+ char *buffer;
struct file_handle *fh;
int dirfd, ret, mnt_id;
struct handle_data *data = (struct handle_data *)ctx->private;
@@ -513,7 +513,9 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
} else {
/* relative to export root */
- dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY);
+ buffer = rpath(ctx, ".");
+ dirfd = open(buffer, O_DIRECTORY);
+ g_free(buffer);
}
if (dirfd < 0) {
return dirfd;
@@ -521,7 +523,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
fh->handle_bytes = data->handle_bytes;
/* add a "./" at the beginning of the path */
- snprintf(buffer, PATH_MAX, "./%s", name);
+ buffer = g_strdup_printf("./%s", name);
/* flag = 0 imply don't follow symlink */
ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
if (!ret) {
@@ -531,6 +533,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
g_free(fh);
}
close(dirfd);
+ g_free(buffer);
return ret;
}
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index df0dbffa7a..56b302c122 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -42,18 +42,18 @@
#define VIRTFS_META_DIR ".virtfs_metadata"
-static const char *local_mapped_attr_path(FsContext *ctx,
- const char *path, char *buffer)
+static char *local_mapped_attr_path(FsContext *ctx, const char *path)
{
char *dir_name;
char *tmp_path = g_strdup(path);
char *base_name = basename(tmp_path);
+ char *buffer;
/* NULL terminate the directory */
dir_name = tmp_path;
*(base_name - 1) = '\0';
- snprintf(buffer, PATH_MAX, "%s/%s/%s/%s",
+ buffer = g_strdup_printf("%s/%s/%s/%s",
ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
g_free(tmp_path);
return buffer;
@@ -92,10 +92,11 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path,
{
FILE *fp;
char buf[ATTR_MAX];
- char attr_path[PATH_MAX];
+ char *attr_path;
- local_mapped_attr_path(ctx, path, attr_path);
+ attr_path = local_mapped_attr_path(ctx, path);
fp = local_fopen(attr_path, "r");
+ g_free(attr_path);
if (!fp) {
return;
}
@@ -118,12 +119,13 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path,
static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
{
int err;
- char buffer[PATH_MAX];
+ char *buffer;
char *path = fs_path->data;
- err = lstat(rpath(fs_ctx, path, buffer), stbuf);
+ buffer = rpath(fs_ctx, path);
+ err = lstat(buffer, stbuf);
if (err) {
- return err;
+ goto err_out;
}
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
/* Actual credentials are part of extended attrs */
@@ -131,41 +133,42 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
gid_t tmp_gid;
mode_t tmp_mode;
dev_t tmp_dev;
- if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
- sizeof(uid_t)) > 0) {
+ if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
stbuf->st_uid = tmp_uid;
}
- if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
- sizeof(gid_t)) > 0) {
+ if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
stbuf->st_gid = tmp_gid;
}
- if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
+ if (getxattr(buffer, "user.virtfs.mode",
&tmp_mode, sizeof(mode_t)) > 0) {
stbuf->st_mode = tmp_mode;
}
- if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
- sizeof(dev_t)) > 0) {
+ if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
stbuf->st_rdev = tmp_dev;
}
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
local_mapped_file_attr(fs_ctx, path, stbuf);
}
+
+err_out:
+ g_free(buffer);
return err;
}
static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
{
int err;
- char attr_dir[PATH_MAX];
+ char *attr_dir;
char *tmp_path = g_strdup(path);
- snprintf(attr_dir, PATH_MAX, "%s/%s/%s",
+ attr_dir = g_strdup_printf("%s/%s/%s",
ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
err = mkdir(attr_dir, 0700);
if (err < 0 && errno == EEXIST) {
err = 0;
}
+ g_free(attr_dir);
g_free(tmp_path);
return err;
}
@@ -176,10 +179,11 @@ static int local_set_mapped_file_attr(FsContext *ctx,
FILE *fp;
int ret = 0;
char buf[ATTR_MAX];
- char attr_path[PATH_MAX];
+ char *attr_path;
int uid = -1, gid = -1, mode = -1, rdev = -1;
- fp = local_fopen(local_mapped_attr_path(ctx, path, attr_path), "r");
+ attr_path = local_mapped_attr_path(ctx, path);
+ fp = local_fopen(attr_path, "r");
if (!fp) {
goto create_map_file;
}
@@ -241,6 +245,7 @@ update_map_file:
fclose(fp);
err_out:
+ g_free(attr_path);
return ret;
}
@@ -282,36 +287,43 @@ static int local_set_xattr(const char *path, FsCred *credp)
static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
FsCred *credp)
{
- char buffer[PATH_MAX];
+ char *buffer;
- if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
- credp->fc_gid) < 0) {
+ buffer = rpath(fs_ctx, path);
+ if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) {
/*
* If we fail to change ownership and if we are
* using security model none. Ignore the error
*/
if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
- return -1;
+ goto err;
}
}
- if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
- return -1;
+ if (chmod(buffer, credp->fc_mode & 07777) < 0) {
+ goto err;
}
+
+ g_free(buffer);
return 0;
+err:
+ g_free(buffer);
+ return -1;
}
static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
char *buf, size_t bufsz)
{
ssize_t tsize = -1;
- char buffer[PATH_MAX];
+ char *buffer;
char *path = fs_path->data;
if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
(fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
int fd;
- fd = open(rpath(fs_ctx, path, buffer), O_RDONLY | O_NOFOLLOW);
+ buffer = rpath(fs_ctx, path);
+ fd = open(buffer, O_RDONLY | O_NOFOLLOW);
+ g_free(buffer);
if (fd == -1) {
return -1;
}
@@ -322,7 +334,9 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
return tsize;
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
+ buffer = rpath(fs_ctx, path);
+ tsize = readlink(buffer, buf, bufsz);
+ g_free(buffer);
}
return tsize;
}
@@ -340,20 +354,24 @@ static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
static int local_open(FsContext *ctx, V9fsPath *fs_path,
int flags, V9fsFidOpenState *fs)
{
- char buffer[PATH_MAX];
+ char *buffer;
char *path = fs_path->data;
- fs->fd = open(rpath(ctx, path, buffer), flags | O_NOFOLLOW);
+ buffer = rpath(ctx, path);
+ fs->fd = open(buffer, flags | O_NOFOLLOW);
+ g_free(buffer);
return fs->fd;
}
static int local_opendir(FsContext *ctx,
V9fsPath *fs_path, V9fsFidOpenState *fs)
{
- char buffer[PATH_MAX];
+ char *buffer;
char *path = fs_path->data;
- fs->dir = opendir(rpath(ctx, path, buffer));
+ buffer = rpath(ctx, path);
+ fs->dir = opendir(buffer);
+ g_free(buffer);
if (!fs->dir) {
return -1;
}
@@ -441,18 +459,23 @@ static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret = -1;
char *path = fs_path->data;
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ buffer = rpath(fs_ctx, path);
+ ret = local_set_xattr(buffer, credp);
+ g_free(buffer);
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
return local_set_mapped_file_attr(fs_ctx, path, credp);
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
+ buffer = rpath(fs_ctx, path);
+ ret = chmod(buffer, credp->fc_mode);
+ g_free(buffer);
}
- return -1;
+ return ret;
}
static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
@@ -462,7 +485,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
int err = -1;
int serrno = 0;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
@@ -470,21 +493,23 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
/* Determine the security model */
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- err = mknod(rpath(fs_ctx, path, buffer),
- SM_LOCAL_MODE_BITS|S_IFREG, 0);
+ buffer = rpath(fs_ctx, path);
+ err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
if (err == -1) {
+ g_free(buffer);
goto out;
}
- err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ err = local_set_xattr(buffer, credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- err = mknod(rpath(fs_ctx, path, buffer),
- SM_LOCAL_MODE_BITS|S_IFREG, 0);
+ buffer = rpath(fs_ctx, path);
+ err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
if (err == -1) {
+ g_free(buffer);
goto out;
}
err = local_set_mapped_file_attr(fs_ctx, path, credp);
@@ -494,9 +519,10 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
}
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
- credp->fc_rdev);
+ buffer = rpath(fs_ctx, path);
+ err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
if (err == -1) {
+ g_free(buffer);
goto out;
}
err = local_post_create_passthrough(fs_ctx, path, credp);
@@ -508,8 +534,9 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
goto out;
err_end:
- remove(rpath(fs_ctx, path, buffer));
+ remove(buffer);
errno = serrno;
+ g_free(buffer);
out:
v9fs_string_free(&fullname);
return err;
@@ -522,7 +549,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
int err = -1;
int serrno = 0;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
@@ -530,19 +557,23 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
/* Determine the security model */
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
+ buffer = rpath(fs_ctx, path);
+ err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
if (err == -1) {
+ g_free(buffer);
goto out;
}
credp->fc_mode = credp->fc_mode|S_IFDIR;
- err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ err = local_set_xattr(buffer, credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
+ buffer = rpath(fs_ctx, path);
+ err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
if (err == -1) {
+ g_free(buffer);
goto out;
}
credp->fc_mode = credp->fc_mode|S_IFDIR;
@@ -553,8 +584,10 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
}
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
+ buffer = rpath(fs_ctx, path);
+ err = mkdir(buffer, credp->fc_mode);
if (err == -1) {
+ g_free(buffer);
goto out;
}
err = local_post_create_passthrough(fs_ctx, path, credp);
@@ -566,8 +599,9 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
goto out;
err_end:
- remove(rpath(fs_ctx, path, buffer));
+ remove(buffer);
errno = serrno;
+ g_free(buffer);
out:
v9fs_string_free(&fullname);
return err;
@@ -626,7 +660,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
int err = -1;
int serrno = 0;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
/*
* Mark all the open to not follow symlinks
@@ -639,21 +673,25 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
/* Determine the security model */
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
+ buffer = rpath(fs_ctx, path);
+ fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
credp->fc_mode = credp->fc_mode|S_IFREG;
/* Set cleint credentials in xattr */
- err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ err = local_set_xattr(buffer, credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
+ buffer = rpath(fs_ctx, path);
+ fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
@@ -666,8 +704,10 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
}
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
+ buffer = rpath(fs_ctx, path);
+ fd = open(buffer, flags, credp->fc_mode);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
@@ -683,8 +723,9 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
err_end:
close(fd);
- remove(rpath(fs_ctx, path, buffer));
+ remove(buffer);
errno = serrno;
+ g_free(buffer);
out:
v9fs_string_free(&fullname);
return err;
@@ -698,7 +739,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
int serrno = 0;
char *newpath;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
@@ -708,10 +749,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
int fd;
ssize_t oldpath_size, write_size;
- fd = open(rpath(fs_ctx, newpath, buffer),
- O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW,
- SM_LOCAL_MODE_BITS);
+ buffer = rpath(fs_ctx, newpath);
+ fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
@@ -730,7 +771,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
close(fd);
/* Set cleint credentials in symlink's xattr */
credp->fc_mode = credp->fc_mode|S_IFLNK;
- err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
+ err = local_set_xattr(buffer, credp);
if (err == -1) {
serrno = errno;
goto err_end;
@@ -738,10 +779,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
int fd;
ssize_t oldpath_size, write_size;
- fd = open(rpath(fs_ctx, newpath, buffer),
- O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW,
- SM_LOCAL_MODE_BITS);
+ buffer = rpath(fs_ctx, newpath);
+ fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
@@ -767,12 +808,13 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
}
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
+ buffer = rpath(fs_ctx, newpath);
+ err = symlink(oldpath, buffer);
if (err) {
+ g_free(buffer);
goto out;
}
- err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
- credp->fc_gid);
+ err = lchown(buffer, credp->fc_uid, credp->fc_gid);
if (err == -1) {
/*
* If we fail to change ownership and if we are
@@ -788,8 +830,9 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
goto out;
err_end:
- remove(rpath(fs_ctx, newpath, buffer));
+ remove(buffer);
errno = serrno;
+ g_free(buffer);
out:
v9fs_string_free(&fullname);
return err;
@@ -800,13 +843,16 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
{
int ret;
V9fsString newpath;
- char buffer[PATH_MAX], buffer1[PATH_MAX];
+ char *buffer, *buffer1;
v9fs_string_init(&newpath);
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
- ret = link(rpath(ctx, oldpath->data, buffer),
- rpath(ctx, newpath.data, buffer1));
+ buffer = rpath(ctx, oldpath->data);
+ buffer1 = rpath(ctx, newpath.data);
+ ret = link(buffer, buffer1);
+ g_free(buffer);
+ g_free(buffer1);
/* now link the virtfs_metadata files */
if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
@@ -815,8 +861,11 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
if (ret < 0) {
goto err_out;
}
- ret = link(local_mapped_attr_path(ctx, oldpath->data, buffer),
- local_mapped_attr_path(ctx, newpath.data, buffer1));
+ buffer = local_mapped_attr_path(ctx, oldpath->data);
+ buffer1 = local_mapped_attr_path(ctx, newpath.data);
+ ret = link(buffer, buffer1);
+ g_free(buffer);
+ g_free(buffer1);
if (ret < 0 && errno != ENOENT) {
goto err_out;
}
@@ -828,17 +877,21 @@ err_out:
static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
char *path = fs_path->data;
- return truncate(rpath(ctx, path, buffer), size);
+ buffer = rpath(ctx, path);
+ ret = truncate(buffer, size);
+ g_free(buffer);
+ return ret;
}
static int local_rename(FsContext *ctx, const char *oldpath,
const char *newpath)
{
int err;
- char buffer[PATH_MAX], buffer1[PATH_MAX];
+ char *buffer, *buffer1;
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
err = local_create_mapped_attr_dir(ctx, newpath);
@@ -846,50 +899,69 @@ static int local_rename(FsContext *ctx, const char *oldpath,
return err;
}
/* rename the .virtfs_metadata files */
- err = rename(local_mapped_attr_path(ctx, oldpath, buffer),
- local_mapped_attr_path(ctx, newpath, buffer1));
+ buffer = local_mapped_attr_path(ctx, oldpath);
+ buffer1 = local_mapped_attr_path(ctx, newpath);
+ err = rename(buffer, buffer1);
+ g_free(buffer);
+ g_free(buffer1);
if (err < 0 && errno != ENOENT) {
return err;
}
}
- return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
+
+ buffer = rpath(ctx, oldpath);
+ buffer1 = rpath(ctx, newpath);
+ err = rename(buffer, buffer1);
+ g_free(buffer);
+ g_free(buffer1);
+ return err;
}
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret = -1;
char *path = fs_path->data;
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
(fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- return lchown(rpath(fs_ctx, path, buffer),
- credp->fc_uid, credp->fc_gid);
+ buffer = rpath(fs_ctx, path);
+ ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
+ g_free(buffer);
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ buffer = rpath(fs_ctx, path);
+ ret = local_set_xattr(buffer, credp);
+ g_free(buffer);
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
return local_set_mapped_file_attr(fs_ctx, path, credp);
}
- return -1;
+ return ret;
}
static int local_utimensat(FsContext *s, V9fsPath *fs_path,
const struct timespec *buf)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
char *path = fs_path->data;
- return qemu_utimens(rpath(s, path, buffer), buf);
+ buffer = rpath(s, path);
+ ret = qemu_utimens(buffer, buf);
+ g_free(buffer);
+ return ret;
}
static int local_remove(FsContext *ctx, const char *path)
{
int err;
struct stat stbuf;
- char buffer[PATH_MAX];
+ char *buffer;
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- err = lstat(rpath(ctx, path, buffer), &stbuf);
+ buffer = rpath(ctx, path);
+ err = lstat(buffer, &stbuf);
+ g_free(buffer);
if (err) {
goto err_out;
}
@@ -898,8 +970,10 @@ static int local_remove(FsContext *ctx, const char *path)
* directory
*/
if (S_ISDIR(stbuf.st_mode)) {
- sprintf(buffer, "%s/%s/%s", ctx->fs_root, path, VIRTFS_META_DIR);
+ buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
+ path, VIRTFS_META_DIR);
err = remove(buffer);
+ g_free(buffer);
if (err < 0 && errno != ENOENT) {
/*
* We didn't had the .virtfs_metadata file. May be file created
@@ -912,7 +986,9 @@ static int local_remove(FsContext *ctx, const char *path)
* Now remove the name from parent directory
* .virtfs_metadata directory
*/
- err = remove(local_mapped_attr_path(ctx, path, buffer));
+ buffer = local_mapped_attr_path(ctx, path);
+ err = remove(buffer);
+ g_free(buffer);
if (err < 0 && errno != ENOENT) {
/*
* We didn't had the .virtfs_metadata file. May be file created
@@ -921,7 +997,10 @@ static int local_remove(FsContext *ctx, const char *path)
goto err_out;
}
}
- return remove(rpath(ctx, path, buffer));
+
+ buffer = rpath(ctx, path);
+ err = remove(buffer);
+ g_free(buffer);
err_out:
return err;
}
@@ -946,10 +1025,14 @@ static int local_fsync(FsContext *ctx, int fid_type,
static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
char *path = fs_path->data;
- return statfs(rpath(s, path, buffer), stbuf);
+ buffer = rpath(s, path);
+ ret = statfs(buffer, stbuf);
+ g_free(buffer);
+ return ret;
}
static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
@@ -1022,7 +1105,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
{
int ret;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
v9fs_string_init(&fullname);
@@ -1033,9 +1116,10 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
* If directory remove .virtfs_metadata contained in the
* directory
*/
- sprintf(buffer, "%s/%s/%s", ctx->fs_root,
- fullname.data, VIRTFS_META_DIR);
+ buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
+ fullname.data, VIRTFS_META_DIR);
ret = remove(buffer);
+ g_free(buffer);
if (ret < 0 && errno != ENOENT) {
/*
* We didn't had the .virtfs_metadata file. May be file created
@@ -1048,7 +1132,9 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
* Now remove the name from parent directory
* .virtfs_metadata directory.
*/
- ret = remove(local_mapped_attr_path(ctx, fullname.data, buffer));
+ buffer = local_mapped_attr_path(ctx, fullname.data);
+ ret = remove(buffer);
+ g_free(buffer);
if (ret < 0 && errno != ENOENT) {
/*
* We didn't had the .virtfs_metadata file. May be file created
@@ -1058,10 +1144,12 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
}
}
/* Remove the name finally */
- ret = remove(rpath(ctx, fullname.data, buffer));
- v9fs_string_free(&fullname);
+ buffer = rpath(ctx, fullname.data);
+ ret = remove(buffer);
+ g_free(buffer);
err_out:
+ v9fs_string_free(&fullname);
return ret;
}
diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c
index 339c5ecae4..803d9d94f3 100644
--- a/hw/9pfs/virtio-9p-posix-acl.c
+++ b/hw/9pfs/virtio-9p-posix-acl.c
@@ -26,8 +26,13 @@
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- char buffer[PATH_MAX];
- return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value, size);
+ char *buffer;
+ ssize_t ret;
+
+ buffer = rpath(ctx, path);
+ ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size);
+ g_free(buffer);
+ return ret;
}
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
@@ -52,17 +57,23 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- char buffer[PATH_MAX];
- return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value,
- size, flags);
+ char *buffer;
+ int ret;
+
+ buffer = rpath(ctx, path);
+ ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags);
+ g_free(buffer);
+ return ret;
}
static int mp_pacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
int ret;
- char buffer[PATH_MAX];
- ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS);
+ char *buffer;
+
+ buffer = rpath(ctx, path);
+ ret = lremovexattr(buffer, MAP_ACL_ACCESS);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
@@ -72,14 +83,20 @@ static int mp_pacl_removexattr(FsContext *ctx,
errno = 0;
ret = 0;
}
+ g_free(buffer);
return ret;
}
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- char buffer[PATH_MAX];
- return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value, size);
+ char *buffer;
+ ssize_t ret;
+
+ buffer = rpath(ctx, path);
+ ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size);
+ g_free(buffer);
+ return ret;
}
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
@@ -104,17 +121,23 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- char buffer[PATH_MAX];
- return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value,
- size, flags);
+ char *buffer;
+ int ret;
+
+ buffer = rpath(ctx, path);
+ ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags);
+ g_free(buffer);
+ return ret;
}
static int mp_dacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
int ret;
- char buffer[PATH_MAX];
- ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT);
+ char *buffer;
+
+ buffer = rpath(ctx, path);
+ ret = lremovexattr(buffer, MAP_ACL_DEFAULT);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
@@ -124,6 +147,7 @@ static int mp_dacl_removexattr(FsContext *ctx,
errno = 0;
ret = 0;
}
+ g_free(buffer);
return ret;
}
diff --git a/hw/9pfs/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c
index e0c92ebf9e..46133e06db 100644
--- a/hw/9pfs/virtio-9p-xattr-user.c
+++ b/hw/9pfs/virtio-9p-xattr-user.c
@@ -21,7 +21,9 @@
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ ssize_t ret;
+
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -30,7 +32,10 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
errno = ENOATTR;
return -1;
}
- return lgetxattr(rpath(ctx, path, buffer), name, value, size);
+ buffer = rpath(ctx, path);
+ ret = lgetxattr(buffer, name, value, size);
+ g_free(buffer);
+ return ret;
}
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
@@ -69,7 +74,9 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
+
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -78,13 +85,18 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
errno = EACCES;
return -1;
}
- return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
+ buffer = rpath(ctx, path);
+ ret = lsetxattr(buffer, name, value, size, flags);
+ g_free(buffer);
+ return ret;
}
static int mp_user_removexattr(FsContext *ctx,
const char *path, const char *name)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
+
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -93,7 +105,10 @@ static int mp_user_removexattr(FsContext *ctx,
errno = EACCES;
return -1;
}
- return lremovexattr(rpath(ctx, path, buffer), name);
+ buffer = rpath(ctx, path);
+ ret = lremovexattr(buffer, name);
+ g_free(buffer);
+ return ret;
}
XattrOperations mapped_user_xattr = {
diff --git a/hw/9pfs/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c
index 3fae557a84..07183887c5 100644
--- a/hw/9pfs/virtio-9p-xattr.c
+++ b/hw/9pfs/virtio-9p-xattr.c
@@ -67,21 +67,24 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
void *value, size_t vsize)
{
ssize_t size = 0;
- char buffer[PATH_MAX];
+ char *buffer;
void *ovalue = value;
XattrOperations *xops;
char *orig_value, *orig_value_start;
ssize_t xattr_len, parsed_len = 0, attr_len;
/* Get the actual len */
- xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0);
+ buffer = rpath(ctx, path);
+ xattr_len = llistxattr(buffer, value, 0);
if (xattr_len <= 0) {
+ g_free(buffer);
return xattr_len;
}
/* Now fetch the xattr and find the actual size */
orig_value = g_malloc(xattr_len);
- xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len);
+ xattr_len = llistxattr(buffer, orig_value, xattr_len);
+ g_free(buffer);
/* store the orig pointer */
orig_value_start = orig_value;
diff --git a/hw/9pfs/virtio-9p-xattr.h b/hw/9pfs/virtio-9p-xattr.h
index 41cc6cbc7b..327b32b5aa 100644
--- a/hw/9pfs/virtio-9p-xattr.h
+++ b/hw/9pfs/virtio-9p-xattr.h
@@ -54,23 +54,38 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- char buffer[PATH_MAX];
- return lgetxattr(rpath(ctx, path, buffer), name, value, size);
+ char *buffer;
+ ssize_t ret;
+
+ buffer = rpath(ctx, path);
+ ret = lgetxattr(buffer, name, value, size);
+ g_free(buffer);
+ return ret;
}
static inline int pt_setxattr(FsContext *ctx, const char *path,
const char *name, void *value,
size_t size, int flags)
{
- char buffer[PATH_MAX];
- return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
+ char *buffer;
+ int ret;
+
+ buffer = rpath(ctx, path);
+ ret = lsetxattr(buffer, name, value, size, flags);
+ g_free(buffer);
+ return ret;
}
static inline int pt_removexattr(FsContext *ctx,
const char *path, const char *name)
{
- char buffer[PATH_MAX];
- return lremovexattr(rpath(ctx, path, buffer), name);
+ char *buffer;
+ int ret;
+
+ buffer = rpath(ctx, path);
+ ret = lremovexattr(path, name);
+ g_free(buffer);
+ return ret;
}
static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 1d6eedb7d8..2c3603aed0 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -6,6 +6,7 @@
#include <sys/time.h>
#include <utime.h>
#include <sys/resource.h>
+#include <glib.h>
#include "hw/virtio/virtio.h"
#include "fsdev/file-op-9p.h"
#include "fsdev/virtio-9p-marshal.h"
@@ -112,10 +113,9 @@ enum p9_proto_version {
#define FID_REFERENCED 0x1
#define FID_NON_RECLAIMABLE 0x2
-static inline const char *rpath(FsContext *ctx, const char *path, char *buffer)
+static inline char *rpath(FsContext *ctx, const char *path)
{
- snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path);
- return buffer;
+ return g_strdup_printf("%s/%s", ctx->fs_root, path);
}
/*
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 05a00dc401..d178b65de4 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -1,4 +1,4 @@
-devices-dirs-$(CONFIG_REALLY_VIRTFS) += 9pfs/
+devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
devices-dirs-$(CONFIG_ACPI) += acpi/
devices-dirs-$(CONFIG_SOFTMMU) += audio/
devices-dirs-$(CONFIG_SOFTMMU) += block/
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index cce7127598..de542010aa 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -110,10 +110,10 @@
#define MP_PHY_88E3015 0x01410E20
/* TX descriptor status */
-#define MP_ETH_TX_OWN (1 << 31)
+#define MP_ETH_TX_OWN (1U << 31)
/* RX descriptor status */
-#define MP_ETH_RX_OWN (1 << 31)
+#define MP_ETH_RX_OWN (1U << 31)
/* Interrupt cause/mask bits */
#define MP_ETH_IRQ_RX_BIT 0
@@ -630,7 +630,7 @@ static int musicpal_lcd_init(SysBusDevice *sbd)
"musicpal-lcd", MP_LCD_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
- s->con = graphic_console_init(dev, &musicpal_gfx_ops, s);
+ s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
qemu_console_resize(s->con, 128*3, 64*3);
qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 47511d2cae..b433748c60 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -809,22 +809,26 @@ static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s,
uint32_t diff, uint32_t value)
{
if (s->compat1509) {
- if (diff & (1 << 31)) /* MCBSP3_CLK_HIZ_DI */
- omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"),
- (value >> 31) & 1);
- if (diff & (1 << 1)) /* CLK32K */
- omap_clk_onoff(omap_findclk(s, "clk32k_out"),
- (~value >> 1) & 1);
+ if (diff & (1U << 31)) {
+ /* MCBSP3_CLK_HIZ_DI */
+ omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), (value >> 31) & 1);
+ }
+ if (diff & (1 << 1)) {
+ /* CLK32K */
+ omap_clk_onoff(omap_findclk(s, "clk32k_out"), (~value >> 1) & 1);
+ }
}
}
static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
uint32_t diff, uint32_t value)
{
- if (diff & (1 << 31)) /* CONF_MOD_UART3_CLK_MODE_R */
- omap_clk_reparent(omap_findclk(s, "uart3_ck"),
- omap_findclk(s, ((value >> 31) & 1) ?
- "ck_48m" : "armper_ck"));
+ if (diff & (1U << 31)) {
+ /* CONF_MOD_UART3_CLK_MODE_R */
+ omap_clk_reparent(omap_findclk(s, "uart3_ck"),
+ omap_findclk(s, ((value >> 31) & 1) ?
+ "ck_48m" : "armper_ck"));
+ }
if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */
omap_clk_reparent(omap_findclk(s, "uart2_ck"),
omap_findclk(s, ((value >> 30) & 1) ?
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 904277a9da..04291488e4 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -259,7 +259,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
case 1:
/* Idle */
- if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */
+ if (!(s->cm_regs[CCCR >> 2] & (1U << 31))) { /* CPDIS */
cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
break;
}
@@ -496,7 +496,7 @@ typedef struct {
#define SSCR0_SSE (1 << 7)
#define SSCR0_RIM (1 << 22)
#define SSCR0_TIM (1 << 23)
-#define SSCR0_MOD (1 << 31)
+#define SSCR0_MOD (1U << 31)
#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
#define SSCR1_RIE (1 << 0)
#define SSCR1_TIE (1 << 1)
@@ -1006,7 +1006,7 @@ static void pxa2xx_rtc_write(void *opaque, hwaddr addr,
switch (addr) {
case RTTR:
- if (!(s->rttr & (1 << 31))) {
+ if (!(s->rttr & (1U << 31))) {
pxa2xx_rtc_hzupdate(s);
s->rttr = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c
index ca77f56c9f..07274285ab 100644
--- a/hw/arm/pxa2xx_gpio.c
+++ b/hw/arm/pxa2xx_gpio.c
@@ -110,7 +110,7 @@ static void pxa2xx_gpio_set(void *opaque, int line, int level)
}
bank = line >> 5;
- mask = 1 << (line & 31);
+ mask = 1U << (line & 31);
if (level) {
s->status[bank] |= s->rising[bank] & mask &
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
index 345fa4a491..d37fb543e8 100644
--- a/hw/arm/pxa2xx_pic.c
+++ b/hw/arm/pxa2xx_pic.c
@@ -105,7 +105,7 @@ static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
irq = s->priority[i] & 0x3f;
- if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) {
+ if ((s->priority[i] & (1U << 31)) && irq < PXA2XX_PIC_SRCS) {
/* Source peripheral ID is valid. */
bit = 1 << (irq & 31);
int_set = (irq >= 32);
@@ -119,7 +119,7 @@ static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
/* IRQ asserted */
ichp &= 0x0000ffff;
- ichp |= (1 << 31) | (irq << 16);
+ ichp |= (1U << 31) | (irq << 16);
}
}
}
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 2237edb4eb..d1c7ad4574 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -358,7 +358,7 @@ static void start_data_plane_bh(void *opaque)
qemu_bh_delete(s->start_bh);
s->start_bh = NULL;
- qemu_thread_create(&s->thread, data_plane_thread,
+ qemu_thread_create(&s->thread, "data_plane", data_plane_thread,
s, QEMU_THREAD_JOINABLE);
}
diff --git a/hw/core/loader.c b/hw/core/loader.c
index e1c3f3a860..b323c0c7b8 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -284,12 +284,30 @@ static void *load_at(int fd, int offset, int size)
#define SZ 64
#include "hw/elf_ops.h"
+const char *load_elf_strerror(int error)
+{
+ switch (error) {
+ case 0:
+ return "No error";
+ case ELF_LOAD_FAILED:
+ return "Failed to load ELF";
+ case ELF_LOAD_NOT_ELF:
+ return "The image is not ELF";
+ case ELF_LOAD_WRONG_ARCH:
+ return "The image is from incompatible architecture";
+ case ELF_LOAD_WRONG_ENDIAN:
+ return "The image has incorrect endianness";
+ default:
+ return "Unknown error";
+ }
+}
+
/* return < 0 if error, otherwise the number of bytes loaded in memory */
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
{
- int fd, data_order, target_data_order, must_swab, ret;
+ int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
uint8_t e_ident[EI_NIDENT];
fd = open(filename, O_RDONLY | O_BINARY);
@@ -302,8 +320,10 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
if (e_ident[0] != ELFMAG0 ||
e_ident[1] != ELFMAG1 ||
e_ident[2] != ELFMAG2 ||
- e_ident[3] != ELFMAG3)
+ e_ident[3] != ELFMAG3) {
+ ret = ELF_LOAD_NOT_ELF;
goto fail;
+ }
#ifdef HOST_WORDS_BIGENDIAN
data_order = ELFDATA2MSB;
#else
@@ -317,6 +337,7 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
}
if (target_data_order != e_ident[EI_DATA]) {
+ ret = ELF_LOAD_WRONG_ENDIAN;
goto fail;
}
@@ -329,12 +350,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
pentry, lowaddr, highaddr, elf_machine, clear_lsb);
}
- close(fd);
- return ret;
-
fail:
close(fd);
- return -1;
+ return ret;
}
static void bswap_uboot_header(uboot_image_header_t *hdr)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index c0b857fbd4..380976a066 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -440,27 +440,33 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
{
const char *typename = object_get_typename(OBJECT(bus));
+ BusClass *bc;
char *buf;
- int i,len;
+ int i, len, bus_id;
bus->parent = parent;
if (name) {
bus->name = g_strdup(name);
} else if (bus->parent && bus->parent->id) {
- /* parent device has id -> use it for bus name */
+ /* parent device has id -> use it plus parent-bus-id for bus name */
+ bus_id = bus->parent->num_child_bus;
+
len = strlen(bus->parent->id) + 16;
buf = g_malloc(len);
- snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
+ snprintf(buf, len, "%s.%d", bus->parent->id, bus_id);
bus->name = buf;
} else {
- /* no id -> use lowercase bus type for bus name */
+ /* no id -> use lowercase bus type plus global bus-id for bus name */
+ bc = BUS_GET_CLASS(bus);
+ bus_id = bc->automatic_ids++;
+
len = strlen(typename) + 16;
buf = g_malloc(len);
- len = snprintf(buf, len, "%s.%d", typename,
- bus->parent ? bus->parent->num_child_bus : 0);
- for (i = 0; i < len; i++)
+ len = snprintf(buf, len, "%s.%d", typename, bus_id);
+ for (i = 0; i < len; i++) {
buf[i] = qemu_tolower(buf[i]);
+ }
bus->name = buf;
}
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 540df82600..7ed76a9c24 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP) += omap_lcdc.o
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
obj-$(CONFIG_SM501) += sm501.o
obj-$(CONFIG_TCX) += tcx.o
+obj-$(CONFIG_CG3) += cg3.o
obj-$(CONFIG_VGA) += vga.o
diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c
index 4a466c8323..55c0ddf00b 100644
--- a/hw/display/blizzard.c
+++ b/hw/display/blizzard.c
@@ -956,7 +956,7 @@ void *s1d13745_init(qemu_irq gpio_int)
s->fb = g_malloc(0x180000);
- s->con = graphic_console_init(NULL, &blizzard_ops, s);
+ s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
new file mode 100644
index 0000000000..a042b9ecbe
--- /dev/null
+++ b/hw/display/cg3.c
@@ -0,0 +1,385 @@
+/*
+ * QEMU CG3 Frame buffer
+ *
+ * Copyright (c) 2012 Bob Breuer
+ * Copyright (c) 2013 Mark Cave-Ayland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "ui/console.h"
+#include "hw/sysbus.h"
+#include "hw/loader.h"
+
+/* Change to 1 to enable debugging */
+#define DEBUG_CG3 0
+
+#define CG3_ROM_FILE "QEMU,cgthree.bin"
+#define FCODE_MAX_ROM_SIZE 0x10000
+
+#define CG3_REG_SIZE 0x20
+
+#define CG3_REG_BT458_ADDR 0x0
+#define CG3_REG_BT458_COLMAP 0x4
+#define CG3_REG_FBC_CTRL 0x10
+#define CG3_REG_FBC_STATUS 0x11
+#define CG3_REG_FBC_CURSTART 0x12
+#define CG3_REG_FBC_CUREND 0x13
+#define CG3_REG_FBC_VCTRL 0x14
+
+/* Control register flags */
+#define CG3_CR_ENABLE_INTS 0x80
+
+/* Status register flags */
+#define CG3_SR_PENDING_INT 0x80
+#define CG3_SR_1152_900_76_B 0x60
+#define CG3_SR_ID_COLOR 0x01
+
+#define CG3_VRAM_SIZE 0x100000
+#define CG3_VRAM_OFFSET 0x800000
+
+#define DPRINTF(fmt, ...) do { \
+ if (DEBUG_CG3) { \
+ printf("CG3: " fmt , ## __VA_ARGS__); \
+ } \
+} while (0);
+
+#define TYPE_CG3 "cgthree"
+#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3)
+
+typedef struct CG3State {
+ SysBusDevice parent_obj;
+
+ QemuConsole *con;
+ qemu_irq irq;
+ hwaddr prom_addr;
+ MemoryRegion vram_mem;
+ MemoryRegion rom;
+ MemoryRegion reg;
+ uint32_t vram_size;
+ int full_update;
+ uint8_t regs[16];
+ uint8_t r[256], g[256], b[256];
+ uint16_t width, height, depth;
+ uint8_t dac_index, dac_state;
+} CG3State;
+
+static void cg3_update_display(void *opaque)
+{
+ CG3State *s = opaque;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ const uint8_t *pix;
+ uint32_t *data;
+ uint32_t dval;
+ int x, y, y_start;
+ unsigned int width, height;
+ ram_addr_t page, page_min, page_max;
+
+ if (surface_bits_per_pixel(surface) != 32) {
+ return;
+ }
+ width = s->width;
+ height = s->height;
+
+ y_start = -1;
+ page_min = -1;
+ page_max = 0;
+ page = 0;
+ pix = memory_region_get_ram_ptr(&s->vram_mem);
+ data = (uint32_t *)surface_data(surface);
+
+ for (y = 0; y < height; y++) {
+ int update = s->full_update;
+
+ page = (y * width) & TARGET_PAGE_MASK;
+ update |= memory_region_get_dirty(&s->vram_mem, page, page + width,
+ DIRTY_MEMORY_VGA);
+ if (update) {
+ if (y_start < 0) {
+ y_start = y;
+ }
+ if (page < page_min) {
+ page_min = page;
+ }
+ if (page > page_max) {
+ page_max = page;
+ }
+
+ for (x = 0; x < width; x++) {
+ dval = *pix++;
+ dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval];
+ *data++ = dval;
+ }
+ } else {
+ if (y_start >= 0) {
+ dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ y_start = -1;
+ }
+ pix += width;
+ data += width;
+ }
+ }
+ s->full_update = 0;
+ if (y_start >= 0) {
+ dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ }
+ if (page_max >= page_min) {
+ memory_region_reset_dirty(&s->vram_mem,
+ page_min, page_max - page_min + TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
+ }
+ /* vsync interrupt? */
+ if (s->regs[0] & CG3_CR_ENABLE_INTS) {
+ s->regs[1] |= CG3_SR_PENDING_INT;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void cg3_invalidate_display(void *opaque)
+{
+ CG3State *s = opaque;
+
+ memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE);
+}
+
+static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
+{
+ CG3State *s = opaque;
+ int val;
+
+ switch (addr) {
+ case CG3_REG_BT458_ADDR:
+ case CG3_REG_BT458_COLMAP:
+ val = 0;
+ break;
+ case CG3_REG_FBC_CTRL:
+ val = s->regs[0];
+ break;
+ case CG3_REG_FBC_STATUS:
+ /* monitor ID 6, board type = 1 (color) */
+ val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
+ break;
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ val = s->regs[addr - 0x10];
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "cg3: Unimplemented register read "
+ "reg 0x%" HWADDR_PRIx " size 0x%x\n",
+ addr, size);
+ val = 0;
+ break;
+ }
+ DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr);
+ return val;
+}
+
+static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ CG3State *s = opaque;
+ uint8_t regval;
+ int i;
+
+ DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n",
+ val, addr, size);
+
+ switch (addr) {
+ case CG3_REG_BT458_ADDR:
+ s->dac_index = val;
+ s->dac_state = 0;
+ break;
+ case CG3_REG_BT458_COLMAP:
+ /* This register can be written to as either a long word or a byte */
+ if (size == 1) {
+ val <<= 24;
+ }
+
+ for (i = 0; i < size; i++) {
+ regval = val >> 24;
+
+ switch (s->dac_state) {
+ case 0:
+ s->r[s->dac_index] = regval;
+ s->dac_state++;
+ break;
+ case 1:
+ s->g[s->dac_index] = regval;
+ s->dac_state++;
+ break;
+ case 2:
+ s->b[s->dac_index] = regval;
+ /* Index autoincrement */
+ s->dac_index = (s->dac_index + 1) & 0xff;
+ default:
+ s->dac_state = 0;
+ break;
+ }
+ val <<= 8;
+ }
+ s->full_update = 1;
+ break;
+ case CG3_REG_FBC_CTRL:
+ s->regs[0] = val;
+ break;
+ case CG3_REG_FBC_STATUS:
+ if (s->regs[1] & CG3_SR_PENDING_INT) {
+ /* clear interrupt */
+ s->regs[1] &= ~CG3_SR_PENDING_INT;
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ s->regs[addr - 0x10] = val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "cg3: Unimplemented register write "
+ "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
+ addr, size, val);
+ break;
+ }
+}
+
+static const MemoryRegionOps cg3_reg_ops = {
+ .read = cg3_reg_read,
+ .write = cg3_reg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static const GraphicHwOps cg3_ops = {
+ .invalidate = cg3_invalidate_display,
+ .gfx_update = cg3_update_display,
+};
+
+static void cg3_realizefn(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ CG3State *s = CG3(dev);
+ int ret;
+ char *fcode_filename;
+
+ /* FCode ROM */
+ memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
+ vmstate_register_ram_global(&s->rom);
+ memory_region_set_readonly(&s->rom, true);
+ sysbus_init_mmio(sbd, &s->rom);
+
+ fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
+ if (fcode_filename) {
+ ret = load_image_targphys(fcode_filename, s->prom_addr,
+ FCODE_MAX_ROM_SIZE);
+ if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
+ error_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
+ }
+ }
+
+ memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
+ CG3_REG_SIZE);
+ sysbus_init_mmio(sbd, &s->reg);
+
+ memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size);
+ vmstate_register_ram_global(&s->vram_mem);
+ sysbus_init_mmio(sbd, &s->vram_mem);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s);
+ qemu_console_resize(s->con, s->width, s->height);
+}
+
+static int vmstate_cg3_post_load(void *opaque, int version_id)
+{
+ CG3State *s = opaque;
+
+ cg3_invalidate_display(s);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_cg3 = {
+ .name = "cg3",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = vmstate_cg3_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(height, CG3State),
+ VMSTATE_UINT16(width, CG3State),
+ VMSTATE_UINT16(depth, CG3State),
+ VMSTATE_BUFFER(r, CG3State),
+ VMSTATE_BUFFER(g, CG3State),
+ VMSTATE_BUFFER(b, CG3State),
+ VMSTATE_UINT8(dac_index, CG3State),
+ VMSTATE_UINT8(dac_state, CG3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void cg3_reset(DeviceState *d)
+{
+ CG3State *s = CG3(d);
+
+ /* Initialize palette */
+ memset(s->r, 0, 256);
+ memset(s->g, 0, 256);
+ memset(s->b, 0, 256);
+
+ s->dac_state = 0;
+ s->full_update = 1;
+ qemu_irq_lower(s->irq);
+}
+
+static Property cg3_properties[] = {
+ DEFINE_PROP_UINT32("vram-size", CG3State, vram_size, -1),
+ DEFINE_PROP_UINT16("width", CG3State, width, -1),
+ DEFINE_PROP_UINT16("height", CG3State, height, -1),
+ DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
+ DEFINE_PROP_UINT64("prom-addr", CG3State, prom_addr, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cg3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = cg3_realizefn;
+ dc->reset = cg3_reset;
+ dc->vmsd = &vmstate_cg3;
+ dc->props = cg3_properties;
+}
+
+static const TypeInfo cg3_info = {
+ .name = TYPE_CG3,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(CG3State),
+ .class_init = cg3_class_init,
+};
+
+static void cg3_register_types(void)
+{
+ type_register_static(&cg3_info);
+}
+
+type_init(cg3_register_types)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 3a8fc0bf8e..0d3127da21 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -2917,7 +2917,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
isa_address_space(isadev),
isa_address_space_io(isadev));
- s->con = graphic_console_init(dev, s->hw_ops, s);
+ s->con = graphic_console_init(dev, 0, s->hw_ops, s);
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
/* XXX ISA-LFB support */
/* FIXME not qdev yet */
@@ -2963,7 +2963,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
vga_common_init(&s->vga, OBJECT(dev));
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
pci_address_space_io(dev));
- s->vga.con = graphic_console_init(DEVICE(dev), s->vga.hw_ops, &s->vga);
+ s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
/* setup PCI */
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 65cca1d707..9750330c25 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1917,7 +1917,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
"exynos4210.fimd", FIMD_REGS_SIZE);
sysbus_init_mmio(dev, &s->iomem);
- s->console = graphic_console_init(DEVICE(dev), &exynos4210_fimd_ops, s);
+ s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s);
return 0;
}
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index bc909bb3de..5c6a2d3605 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -484,7 +484,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
{
s->vram = g_malloc0(s->vram_size);
- s->con = graphic_console_init(dev, &g364fb_ops, s);
+ s->con = graphic_console_init(dev, 0, &g364fb_ops, s);
memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index 8407e6c2ef..f9e7d7c981 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -271,7 +271,7 @@ static int jazz_led_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
sysbus_init_mmio(dev, &s->iomem);
- s->con = graphic_console_init(DEVICE(dev), &jazz_led_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s);
return 0;
}
diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c
index 5150cb48b7..603537aabb 100644
--- a/hw/display/milkymist-vgafb.c
+++ b/hw/display/milkymist-vgafb.c
@@ -290,7 +290,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev)
"milkymist-vgafb", R_MAX * 4);
sysbus_init_mmio(dev, &s->regs_region);
- s->con = graphic_console_init(DEVICE(dev), &vgafb_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s);
return 0;
}
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
index c3b9b68971..fda81baff0 100644
--- a/hw/display/omap_lcdc.c
+++ b/hw/display/omap_lcdc.c
@@ -406,7 +406,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
memory_region_add_subregion(sysmem, base, &s->iomem);
- s->con = graphic_console_init(NULL, &omap_ops, s);
+ s->con = graphic_console_init(NULL, 0, &omap_ops, s);
return s;
}
diff --git a/hw/display/pl110.c b/hw/display/pl110.c
index ab689e9aae..c574cf1a81 100644
--- a/hw/display/pl110.c
+++ b/hw/display/pl110.c
@@ -464,7 +464,7 @@ static int pl110_initfn(SysBusDevice *sbd)
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
- s->con = graphic_console_init(dev, &pl110_gfx_ops, s);
+ s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
return 0;
}
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
index 990931ae45..09cdf17ab9 100644
--- a/hw/display/pxa2xx_lcd.c
+++ b/hw/display/pxa2xx_lcd.c
@@ -1013,7 +1013,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
"pxa2xx-lcd-controller", 0x00100000);
memory_region_add_subregion(sysmem, base, &s->iomem);
- s->con = graphic_console_init(NULL, &pxa2xx_ops, s);
+ s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 2a559ebcc9..47bbf1f1fe 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2069,7 +2069,7 @@ static int qxl_init_primary(PCIDevice *dev)
portio_list_set_flush_coalesced(qxl_vga_port_list);
portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
- vga->con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
+ vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
qemu_spice_display_init_common(&qxl->ssd);
rc = qxl_init_common(qxl);
@@ -2094,7 +2094,7 @@ static int qxl_init_secondary(PCIDevice *dev)
qxl->vga.vram_size);
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
- qxl->vga.con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
+ qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
return qxl_init_common(qxl);
}
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 0b5f993594..eedf2d48e0 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1449,5 +1449,5 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
}
/* create qemu graphic console */
- s->con = graphic_console_init(DEVICE(dev), &sm501_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
}
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index 89804e108b..c2eea04934 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -299,7 +299,7 @@ static int ssd0303_init(I2CSlave *i2c)
{
ssd0303_state *s = SSD0303(i2c);
- s->con = graphic_console_init(DEVICE(i2c), &ssd0303_ops, s);
+ s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s);
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
return 0;
}
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index c3231c6116..46c3b40c79 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -342,7 +342,7 @@ static int ssd0323_init(SSISlave *dev)
s->col_end = 63;
s->row_end = 79;
- s->con = graphic_console_init(DEVICE(dev), &ssd0323_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s);
qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 3dd9b98eca..f4011d2db0 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -587,7 +587,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
s->scr_width = 480;
s->scr_height = 640;
- s->con = graphic_console_init(NULL, &tc6393xb_gfx_ops, s);
+ s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
return s;
}
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index e60769c2c9..2b37ffac4c 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -602,14 +602,14 @@ static int tcx_init1(SysBusDevice *dev)
&s->vram_mem, vram_offset, size);
sysbus_init_mmio(dev, &s->vram_cplane);
- s->con = graphic_console_init(DEVICE(dev), &tcx24_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s);
} else {
/* THC 8 bit (dummy) */
memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8",
TCX_THC_NREGS_8);
sysbus_init_mmio(dev, &s->thc8);
- s->con = graphic_console_init(DEVICE(dev), &tcx_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s);
}
qemu_console_resize(s->con, s->width, s->height);
diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c
index 8b514cc39d..afc46b8c9d 100644
--- a/hw/display/vga-isa-mm.c
+++ b/hw/display/vga-isa-mm.c
@@ -135,7 +135,7 @@ int isa_vga_mm_init(hwaddr vram_base,
vga_common_init(&s->vga, NULL);
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
- s->vga.con = graphic_console_init(NULL, s->vga.hw_ops, s);
+ s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
vga_init_vbe(&s->vga, NULL, address_space);
return 0;
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index c2a19ad6ba..1d9ea6b51d 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -67,7 +67,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
isa_mem_base + 0x000a0000,
vga_io_memory, 1);
memory_region_set_coalescing(vga_io_memory);
- s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev));
/* ROM BIOS */
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index f74fc43aa6..574ea0e7f9 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -151,7 +151,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
true);
- s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
/* XXX: VGA_RAM_SIZE must be a power of two */
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 334e71856e..bd2c108c42 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1199,7 +1199,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
s->scratch_size = SVGA_SCRATCH_SIZE;
s->scratch = g_malloc(s->scratch_size * 4);
- s->vga.con = graphic_console_init(dev, &vmsvga_ops, s);
+ s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s);
s->fifo_size = SVGA_FIFO_SIZE;
memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index cb9d456814..032eb7a9a5 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -992,7 +992,7 @@ wait_more:
/* vfb */
fb = container_of(xfb, struct XenFB, c.xendev);
- fb->c.con = graphic_console_init(NULL, &xenfb_ops, fb);
+ fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
fb->have_console = 1;
/* vkbd */
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b1a7ebb8e3..b667d31de5 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -643,6 +643,21 @@ static inline char acpi_get_hex(uint32_t val)
#define ACPI_PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start)
#define ACPI_PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)
+#define ACPI_PCINOHP_OFFSET_HEX (*ssdt_pcinohp_name - *ssdt_pcinohp_start + 1)
+#define ACPI_PCINOHP_OFFSET_ADR (*ssdt_pcinohp_adr - *ssdt_pcinohp_start)
+#define ACPI_PCINOHP_SIZEOF (*ssdt_pcinohp_end - *ssdt_pcinohp_start)
+#define ACPI_PCINOHP_AML (ssdp_pcihp_aml + *ssdt_pcinohp_start)
+
+#define ACPI_PCIVGA_OFFSET_HEX (*ssdt_pcivga_name - *ssdt_pcivga_start + 1)
+#define ACPI_PCIVGA_OFFSET_ADR (*ssdt_pcivga_adr - *ssdt_pcivga_start)
+#define ACPI_PCIVGA_SIZEOF (*ssdt_pcivga_end - *ssdt_pcivga_start)
+#define ACPI_PCIVGA_AML (ssdp_pcihp_aml + *ssdt_pcivga_start)
+
+#define ACPI_PCIQXL_OFFSET_HEX (*ssdt_pciqxl_name - *ssdt_pciqxl_start + 1)
+#define ACPI_PCIQXL_OFFSET_ADR (*ssdt_pciqxl_adr - *ssdt_pciqxl_start)
+#define ACPI_PCIQXL_SIZEOF (*ssdt_pciqxl_end - *ssdt_pciqxl_start)
+#define ACPI_PCIQXL_AML (ssdp_pcihp_aml + *ssdt_pciqxl_start)
+
#define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */
#define ACPI_SSDT_HEADER_LENGTH 36
@@ -677,6 +692,33 @@ static void patch_pcihp(int slot, uint8_t *ssdt_ptr)
ssdt_ptr[ACPI_PCIHP_OFFSET_ADR + 2] = slot;
}
+static void patch_pcinohp(int slot, uint8_t *ssdt_ptr)
+{
+ unsigned devfn = PCI_DEVFN(slot, 0);
+
+ ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
+ ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX + 1] = acpi_get_hex(devfn);
+ ssdt_ptr[ACPI_PCINOHP_OFFSET_ADR + 2] = slot;
+}
+
+static void patch_pcivga(int slot, uint8_t *ssdt_ptr)
+{
+ unsigned devfn = PCI_DEVFN(slot, 0);
+
+ ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
+ ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX + 1] = acpi_get_hex(devfn);
+ ssdt_ptr[ACPI_PCIVGA_OFFSET_ADR + 2] = slot;
+}
+
+static void patch_pciqxl(int slot, uint8_t *ssdt_ptr)
+{
+ unsigned devfn = PCI_DEVFN(slot, 0);
+
+ ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
+ ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX + 1] = acpi_get_hex(devfn);
+ ssdt_ptr[ACPI_PCIQXL_OFFSET_ADR + 2] = slot;
+}
+
/* Assign BSEL property to all buses. In the future, this can be changed
* to only assign to buses that support hotplug.
*/
@@ -737,6 +779,10 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
AcpiBuildPciBusHotplugState *parent = child->parent;
GArray *bus_table = build_alloc_array();
DECLARE_BITMAP(slot_hotplug_enable, PCI_SLOT_MAX);
+ DECLARE_BITMAP(slot_device_present, PCI_SLOT_MAX);
+ DECLARE_BITMAP(slot_device_system, PCI_SLOT_MAX);
+ DECLARE_BITMAP(slot_device_vga, PCI_SLOT_MAX);
+ DECLARE_BITMAP(slot_device_qxl, PCI_SLOT_MAX);
uint8_t op;
int i;
QObject *bsel;
@@ -764,40 +810,82 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
build_append_byte(bus_table, 0x08); /* NameOp */
build_append_nameseg(bus_table, "BSEL");
build_append_int(bus_table, qint_get_int(qobject_to_qint(bsel)));
-
memset(slot_hotplug_enable, 0xff, sizeof slot_hotplug_enable);
+ } else {
+ /* No bsel - no slots are hot-pluggable */
+ memset(slot_hotplug_enable, 0x00, sizeof slot_hotplug_enable);
+ }
- for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
- DeviceClass *dc;
- PCIDeviceClass *pc;
- PCIDevice *pdev = bus->devices[i];
+ memset(slot_device_present, 0x00, sizeof slot_device_present);
+ memset(slot_device_system, 0x00, sizeof slot_device_present);
+ memset(slot_device_vga, 0x00, sizeof slot_device_vga);
+ memset(slot_device_qxl, 0x00, sizeof slot_device_qxl);
- if (!pdev) {
- continue;
- }
+ for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) {
+ DeviceClass *dc;
+ PCIDeviceClass *pc;
+ PCIDevice *pdev = bus->devices[i];
+ int slot = PCI_SLOT(i);
- pc = PCI_DEVICE_GET_CLASS(pdev);
- dc = DEVICE_GET_CLASS(pdev);
+ if (!pdev) {
+ continue;
+ }
- if (!dc->hotpluggable || pc->is_bridge) {
- int slot = PCI_SLOT(i);
+ set_bit(slot, slot_device_present);
+ pc = PCI_DEVICE_GET_CLASS(pdev);
+ dc = DEVICE_GET_CLASS(pdev);
- clear_bit(slot, slot_hotplug_enable);
- }
+ if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
+ set_bit(slot, slot_device_system);
}
- /* Append Device object for each slot which supports eject */
- for (i = 0; i < PCI_SLOT_MAX; i++) {
- bool can_eject = test_bit(i, slot_hotplug_enable);
- if (can_eject) {
- void *pcihp = acpi_data_push(bus_table,
- ACPI_PCIHP_SIZEOF);
- memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF);
- patch_pcihp(i, pcihp);
- bus_hotplug_support = true;
+ if (pc->class_id == PCI_CLASS_DISPLAY_VGA) {
+ set_bit(slot, slot_device_vga);
+
+ if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) {
+ set_bit(slot, slot_device_qxl);
}
}
+ if (!dc->hotpluggable || pc->is_bridge) {
+ clear_bit(slot, slot_hotplug_enable);
+ }
+ }
+
+ /* Append Device object for each slot */
+ for (i = 0; i < PCI_SLOT_MAX; i++) {
+ bool can_eject = test_bit(i, slot_hotplug_enable);
+ bool present = test_bit(i, slot_device_present);
+ bool vga = test_bit(i, slot_device_vga);
+ bool qxl = test_bit(i, slot_device_qxl);
+ bool system = test_bit(i, slot_device_system);
+ if (can_eject) {
+ void *pcihp = acpi_data_push(bus_table,
+ ACPI_PCIHP_SIZEOF);
+ memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF);
+ patch_pcihp(i, pcihp);
+ bus_hotplug_support = true;
+ } else if (qxl) {
+ void *pcihp = acpi_data_push(bus_table,
+ ACPI_PCIQXL_SIZEOF);
+ memcpy(pcihp, ACPI_PCIQXL_AML, ACPI_PCIQXL_SIZEOF);
+ patch_pciqxl(i, pcihp);
+ } else if (vga) {
+ void *pcihp = acpi_data_push(bus_table,
+ ACPI_PCIVGA_SIZEOF);
+ memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF);
+ patch_pcivga(i, pcihp);
+ } else if (system) {
+ /* Nothing to do: system devices are in DSDT. */
+ } else if (present) {
+ void *pcihp = acpi_data_push(bus_table,
+ ACPI_PCINOHP_SIZEOF);
+ memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF);
+ patch_pcinohp(i, pcihp);
+ }
+ }
+
+ if (bsel) {
method = build_alloc_method("DVNT", 2);
for (i = 0; i < PCI_SLOT_MAX; i++) {
@@ -976,7 +1064,14 @@ build_ssdt(GArray *table_data, GArray *linker,
{
AcpiBuildPciBusHotplugState hotplug_state;
- PCIBus *bus = find_i440fx(); /* TODO: Q35 support */
+ Object *pci_host;
+ PCIBus *bus = NULL;
+ bool ambiguous;
+
+ pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
+ if (!ambiguous && pci_host) {
+ bus = PCI_HOST_BRIDGE(pci_host)->bus;
+ }
build_pci_bus_state_init(&hotplug_state, NULL);
diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl
index b23d5e0eac..0a1e252d21 100644
--- a/hw/i386/acpi-dsdt.dsl
+++ b/hw/i386/acpi-dsdt.dsl
@@ -80,6 +80,8 @@ DefinitionBlock (
Name(_HID, EisaId("PNP0A03"))
Name(_ADR, 0x00)
Name(_UID, 1)
+//#define PX13 S0B_
+// External(PX13, DeviceObj)
}
}
@@ -88,34 +90,6 @@ DefinitionBlock (
/****************************************************************
- * VGA
- ****************************************************************/
-
- Scope(\_SB.PCI0) {
- Device(VGA) {
- Name(_ADR, 0x00020000)
- OperationRegion(PCIC, PCI_Config, Zero, 0x4)
- Field(PCIC, DWordAcc, NoLock, Preserve) {
- VEND, 32
- }
- Method(_S1D, 0, NotSerialized) {
- Return (0x00)
- }
- Method(_S2D, 0, NotSerialized) {
- Return (0x00)
- }
- Method(_S3D, 0, NotSerialized) {
- If (LEqual(VEND, 0x1001b36)) {
- Return (0x03) // QXL
- } Else {
- Return (0x00)
- }
- }
- }
- }
-
-
-/****************************************************************
* PIIX4 PM
****************************************************************/
@@ -132,6 +106,9 @@ DefinitionBlock (
****************************************************************/
Scope(\_SB.PCI0) {
+
+ External(ISA, DeviceObj)
+
Device(ISA) {
Name(_ADR, 0x00010000)
diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated
index 1e58801b2a..94c6e8e114 100644
--- a/hw/i386/acpi-dsdt.hex.generated
+++ b/hw/i386/acpi-dsdt.hex.generated
@@ -3,12 +3,12 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x53,
0x44,
0x54,
-0x87,
+0x85,
0x11,
0x0,
0x0,
0x1,
-0xb8,
+0x8b,
0x42,
0x58,
0x50,
@@ -146,7 +146,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x1,
0x10,
0x4e,
-0x15,
+0x18,
0x2e,
0x5f,
0x53,
@@ -163,9 +163,9 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x53,
0x11,
0x42,
-0x7,
0xa,
-0x6e,
+0xa,
+0x9e,
0x88,
0xd,
0x0,
@@ -217,11 +217,59 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x0,
0xd,
0xff,
+0xad,
+0x0,
+0x0,
+0x0,
+0xa1,
+0x88,
+0xd,
+0x0,
+0x1,
+0xc,
+0x3,
+0x0,
+0x0,
+0xf,
+0xae,
0xff,
+0xae,
+0x0,
0x0,
+0xf1,
0x0,
+0x88,
+0xd,
+0x0,
+0x1,
+0xc,
+0x3,
0x0,
-0xf3,
+0x0,
+0x20,
+0xaf,
+0xdf,
+0xaf,
+0x0,
+0x0,
+0xc0,
+0x0,
+0x88,
+0xd,
+0x0,
+0x1,
+0xc,
+0x3,
+0x0,
+0x0,
+0xe4,
+0xaf,
+0xff,
+0xff,
+0x0,
+0x0,
+0x1c,
+0x50,
0x87,
0x17,
0x0,
@@ -347,7 +395,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x45,
0x53,
0xa,
-0x5c,
+0x8c,
0x50,
0x53,
0x33,
@@ -358,7 +406,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x45,
0x53,
0xa,
-0x60,
+0x90,
0x50,
0x45,
0x33,
@@ -369,7 +417,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x45,
0x53,
0xa,
-0x68,
+0x98,
0x50,
0x4c,
0x33,
@@ -638,103 +686,6 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x79,
0x0,
0x10,
-0x40,
-0x6,
-0x2e,
-0x5f,
-0x53,
-0x42,
-0x5f,
-0x50,
-0x43,
-0x49,
-0x30,
-0x5b,
-0x82,
-0x43,
-0x5,
-0x56,
-0x47,
-0x41,
-0x5f,
-0x8,
-0x5f,
-0x41,
-0x44,
-0x52,
-0xc,
-0x0,
-0x0,
-0x2,
-0x0,
-0x5b,
-0x80,
-0x50,
-0x43,
-0x49,
-0x43,
-0x2,
-0x0,
-0xa,
-0x4,
-0x5b,
-0x81,
-0xb,
-0x50,
-0x43,
-0x49,
-0x43,
-0x3,
-0x56,
-0x45,
-0x4e,
-0x44,
-0x20,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x31,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x32,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x14,
-0x19,
-0x5f,
-0x53,
-0x33,
-0x44,
-0x0,
-0xa0,
-0xe,
-0x93,
-0x56,
-0x45,
-0x4e,
-0x44,
-0xc,
-0x36,
-0x1b,
-0x0,
-0x1,
-0xa4,
-0xa,
-0x3,
-0xa1,
-0x3,
-0xa4,
-0x0,
-0x10,
0x25,
0x2e,
0x5f,
@@ -860,7 +811,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x4e,
0x1,
0x10,
-0x4b,
+0x4a,
0x1e,
0x2f,
0x3,
@@ -878,7 +829,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x5f,
0x5b,
0x82,
-0x2d,
+0x2c,
0x53,
0x4d,
0x43,
@@ -898,9 +849,8 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x53,
0x54,
0x41,
-0xb,
-0x0,
-0xff,
+0xa,
+0xf0,
0x8,
0x5f,
0x43,
@@ -4061,7 +4011,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x1,
0x10,
0x47,
-0xe,
+0x11,
0x5f,
0x53,
0x42,
@@ -4291,6 +4241,54 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x3,
0x75,
0x60,
+0x5b,
+0x82,
+0x2e,
+0x50,
+0x52,
+0x45,
+0x53,
+0x8,
+0x5f,
+0x48,
+0x49,
+0x44,
+0xd,
+0x41,
+0x43,
+0x50,
+0x49,
+0x30,
+0x30,
+0x30,
+0x34,
+0x0,
+0x8,
+0x5f,
+0x43,
+0x52,
+0x53,
+0x11,
+0xd,
+0xa,
+0xa,
+0x47,
+0x1,
+0x0,
+0xaf,
+0x0,
+0xaf,
+0x0,
+0x20,
+0x79,
+0x0,
+0x8,
+0x5f,
+0x53,
+0x54,
+0x41,
+0xa,
+0xb,
0x10,
0x42,
0xc,
@@ -4488,5 +4486,5 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x0
};
static unsigned short piix_dsdt_applesmc_sta[] = {
-0x384
+0x353
};
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index d5dc1ef336..ae1699d6db 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -221,10 +221,16 @@ static void pc_init1(QEMUMachineInitArgs *args,
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
+ char busname[] = "ide.0";
dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
ide_irq[i],
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
- idebus[i] = qdev_get_child_bus(DEVICE(dev), "ide.0");
+ /*
+ * The ide bus name is ide.0 for the first bus and ide.1 for the
+ * second one.
+ */
+ busname[4] = '0' + i;
+ idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
}
}
diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl
index d618e9e2d2..f4d2a2daee 100644
--- a/hw/i386/q35-acpi-dsdt.dsl
+++ b/hw/i386/q35-acpi-dsdt.dsl
@@ -72,6 +72,8 @@ DefinitionBlock (
Name(_ADR, 0x00)
Name(_UID, 1)
+ External(ISA, DeviceObj)
+
// _OSC: based on sample of ACPI3.0b spec
Name(SUPP, 0) // PCI _OSC Support Field value
Name(CTRL, 0) // PCI _OSC Control Field value
@@ -134,34 +136,13 @@ DefinitionBlock (
/****************************************************************
- * VGA
- ****************************************************************/
-
- Scope(\_SB.PCI0) {
- Device(VGA) {
- Name(_ADR, 0x00010000)
- Method(_S1D, 0, NotSerialized) {
- Return (0x00)
- }
- Method(_S2D, 0, NotSerialized) {
- Return (0x00)
- }
- Method(_S3D, 0, NotSerialized) {
- Return (0x00)
- }
- }
- }
-
-
-/****************************************************************
* LPC ISA bridge
****************************************************************/
Scope(\_SB.PCI0) {
/* PCI D31:f0 LPC ISA bridge */
Device(ISA) {
- /* PCI D31:f0 */
- Name(_ADR, 0x001f0000)
+ Name (_ADR, 0x001F0000) // _ADR: Address
/* ICH9 PCI to ISA irq remapping */
OperationRegion(PIRQ, PCI_Config, 0x60, 0x0C)
diff --git a/hw/i386/q35-acpi-dsdt.hex.generated b/hw/i386/q35-acpi-dsdt.hex.generated
index 6d885a9055..6c29f3b6d2 100644
--- a/hw/i386/q35-acpi-dsdt.hex.generated
+++ b/hw/i386/q35-acpi-dsdt.hex.generated
@@ -3,12 +3,12 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x53,
0x44,
0x54,
-0xdf,
+0xd7,
0x1c,
0x0,
0x0,
0x1,
-0xff,
+0x3e,
0x42,
0x58,
0x50,
@@ -415,11 +415,11 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x0,
0x0,
0x0,
-0xf7,
+0xd7,
0xc,
0x0,
0x0,
-0xf8,
+0xd8,
0xc,
0x88,
0xd,
@@ -853,61 +853,6 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x79,
0x0,
0x10,
-0x36,
-0x2e,
-0x5f,
-0x53,
-0x42,
-0x5f,
-0x50,
-0x43,
-0x49,
-0x30,
-0x5b,
-0x82,
-0x2a,
-0x56,
-0x47,
-0x41,
-0x5f,
-0x8,
-0x5f,
-0x41,
-0x44,
-0x52,
-0xc,
-0x0,
-0x0,
-0x1,
-0x0,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x31,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x32,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x33,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x10,
0x4c,
0x7,
0x2e,
@@ -1033,7 +978,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x4e,
0x1,
0x10,
-0x4b,
+0x4a,
0x1e,
0x2f,
0x3,
@@ -1051,7 +996,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x5f,
0x5b,
0x82,
-0x2d,
+0x2c,
0x53,
0x4d,
0x43,
@@ -1071,9 +1016,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x53,
0x54,
0x41,
-0xb,
-0x0,
-0xff,
+0xa,
+0xf0,
0x8,
0x5f,
0x43,
@@ -7016,7 +6960,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x1,
0x10,
0x47,
-0xe,
+0x11,
0x5f,
0x53,
0x42,
@@ -7121,8 +7065,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x54,
0x1,
0xb,
-0x0,
-0xaf,
+0xd8,
+0xc,
0xa,
0x20,
0x5b,
@@ -7246,6 +7190,54 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x3,
0x75,
0x60,
+0x5b,
+0x82,
+0x2e,
+0x50,
+0x52,
+0x45,
+0x53,
+0x8,
+0x5f,
+0x48,
+0x49,
+0x44,
+0xd,
+0x41,
+0x43,
+0x50,
+0x49,
+0x30,
+0x30,
+0x30,
+0x34,
+0x0,
+0x8,
+0x5f,
+0x43,
+0x52,
+0x53,
+0x11,
+0xd,
+0xa,
+0xa,
+0x47,
+0x1,
+0xd8,
+0xc,
+0xd8,
+0xc,
+0x0,
+0x20,
+0x79,
+0x0,
+0x8,
+0x5f,
+0x53,
+0x54,
+0x41,
+0xa,
+0xb,
0x10,
0x4f,
0x8,
@@ -7392,5 +7384,5 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x0
};
static unsigned short q35_dsdt_applesmc_sta[] = {
-0x431
+0x3fa
};
diff --git a/hw/i386/ssdt-pcihp.dsl b/hw/i386/ssdt-pcihp.dsl
index cc245c3e7c..ac91c05836 100644
--- a/hw/i386/ssdt-pcihp.dsl
+++ b/hw/i386/ssdt-pcihp.dsl
@@ -46,5 +46,55 @@ DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPCIHP", 0x1)
}
}
+ ACPI_EXTRACT_DEVICE_START ssdt_pcinohp_start
+ ACPI_EXTRACT_DEVICE_END ssdt_pcinohp_end
+ ACPI_EXTRACT_DEVICE_STRING ssdt_pcinohp_name
+
+ // Extract the offsets of the device name, address dword and the slot
+ // name byte - we fill them in for each device.
+ Device(SBB) {
+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcinohp_adr
+ Name(_ADR, 0xAA0000)
+ }
+
+ ACPI_EXTRACT_DEVICE_START ssdt_pcivga_start
+ ACPI_EXTRACT_DEVICE_END ssdt_pcivga_end
+ ACPI_EXTRACT_DEVICE_STRING ssdt_pcivga_name
+
+ // Extract the offsets of the device name, address dword and the slot
+ // name byte - we fill them in for each device.
+ Device(SCC) {
+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcivga_adr
+ Name(_ADR, 0xAA0000)
+ Method(_S1D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S2D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S3D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ }
+
+ ACPI_EXTRACT_DEVICE_START ssdt_pciqxl_start
+ ACPI_EXTRACT_DEVICE_END ssdt_pciqxl_end
+ ACPI_EXTRACT_DEVICE_STRING ssdt_pciqxl_name
+
+ // Extract the offsets of the device name, address dword and the slot
+ // name byte - we fill them in for each device.
+ Device(SDD) {
+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pciqxl_adr
+ Name(_ADR, 0xAA0000)
+ Method(_S1D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S2D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S3D, 0, NotSerialized) {
+ Return (0x03) // QXL
+ }
+ }
}
}
diff --git a/hw/i386/ssdt-pcihp.hex.generated b/hw/i386/ssdt-pcihp.hex.generated
index 610a631fd1..b599b4663c 100644
--- a/hw/i386/ssdt-pcihp.hex.generated
+++ b/hw/i386/ssdt-pcihp.hex.generated
@@ -1,23 +1,38 @@
static unsigned char ssdt_pcihp_name[] = {
-0x33
+0x34
+};
+static unsigned char ssdt_pcivga_end[] = {
+0x99
+};
+static unsigned char ssdt_pcivga_name[] = {
+0x70
};
static unsigned char ssdt_pcihp_adr[] = {
-0x44
+0x45
+};
+static unsigned char ssdt_pcinohp_end[] = {
+0x6d
};
static unsigned char ssdt_pcihp_end[] = {
-0x5b
+0x5c
+};
+static unsigned char ssdt_pciqxl_start[] = {
+0x99
+};
+static unsigned char ssdt_pcinohp_name[] = {
+0x5f
};
static unsigned char ssdp_pcihp_aml[] = {
0x53,
0x53,
0x44,
0x54,
-0x5b,
+0xc6,
0x0,
0x0,
0x0,
0x1,
-0xe8,
+0x6b,
0x42,
0x58,
0x50,
@@ -45,7 +60,8 @@ static unsigned char ssdp_pcihp_aml[] = {
0x13,
0x20,
0x10,
-0x36,
+0x41,
+0xa,
0x5c,
0x2e,
0x5f,
@@ -98,11 +114,138 @@ static unsigned char ssdp_pcihp_aml[] = {
0x5f,
0x53,
0x55,
-0x4e
+0x4e,
+0x5b,
+0x82,
+0xf,
+0x53,
+0x42,
+0x42,
+0x5f,
+0x8,
+0x5f,
+0x41,
+0x44,
+0x52,
+0xc,
+0x0,
+0x0,
+0xaa,
+0x0,
+0x5b,
+0x82,
+0x2a,
+0x53,
+0x43,
+0x43,
+0x5f,
+0x8,
+0x5f,
+0x41,
+0x44,
+0x52,
+0xc,
+0x0,
+0x0,
+0xaa,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x31,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x32,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x33,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x5b,
+0x82,
+0x2b,
+0x53,
+0x44,
+0x44,
+0x5f,
+0x8,
+0x5f,
+0x41,
+0x44,
+0x52,
+0xc,
+0x0,
+0x0,
+0xaa,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x31,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x32,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x14,
+0x9,
+0x5f,
+0x53,
+0x33,
+0x44,
+0x0,
+0xa4,
+0xa,
+0x3
+};
+static unsigned char ssdt_pciqxl_adr[] = {
+0xa6
+};
+static unsigned char ssdt_pcinohp_adr[] = {
+0x69
+};
+static unsigned char ssdt_pcivga_adr[] = {
+0x7a
+};
+static unsigned char ssdt_pciqxl_name[] = {
+0x9c
+};
+static unsigned char ssdt_pcivga_start[] = {
+0x6d
+};
+static unsigned char ssdt_pciqxl_end[] = {
+0xc6
};
static unsigned char ssdt_pcihp_start[] = {
-0x30
+0x31
};
static unsigned char ssdt_pcihp_id[] = {
-0x3d
+0x3e
+};
+static unsigned char ssdt_pcinohp_start[] = {
+0x5c
};
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 20e412c240..9a4064f892 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -40,7 +40,7 @@
#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
AHCI_RX_FIS_SZ)
-#define AHCI_IRQ_ON_SG (1 << 31)
+#define AHCI_IRQ_ON_SG (1U << 31)
#define AHCI_CMD_ATAPI (1 << 5)
#define AHCI_CMD_WRITE (1 << 6)
#define AHCI_CMD_PREFETCH (1 << 7)
@@ -61,7 +61,7 @@
/* HOST_CTL bits */
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
-#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */
+#define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */
/* HOST_CAP bits */
#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
@@ -69,7 +69,7 @@
#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
-#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */
+#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
@@ -89,7 +89,7 @@
#define PORT_RESERVED 0x3c /* reserved */
/* PORT_IRQ_{STAT,MASK} bits */
-#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
+#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
@@ -151,7 +151,7 @@
#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
-#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */
+#define PORT_IRQ_STAT_CPDS (1U << 31) /* Code Port Detect Status */
/* ap->flags bits */
#define AHCI_FLAG_NO_NCQ (1 << 24)
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index 655b8c5011..29af3d741f 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -281,7 +281,7 @@ static void kbd_write_command(void *opaque, hwaddr addr,
kbd_update_irq(s);
break;
case KBD_CCMD_READ_INPORT:
- kbd_queue(s, 0x00, 0);
+ kbd_queue(s, 0x80, 0);
break;
case KBD_CCMD_READ_OUTPORT:
kbd_queue(s, s->outport, 0);
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 60eb936e0d..c8a2318d56 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -25,3 +25,4 @@ obj-$(CONFIG_SH4) += sh_intc.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
+obj-$(CONFIG_S390_FLIC) += s390_flic.o
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 652dd47a1c..b527932382 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -93,9 +93,6 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
uint32_t mask = 1 << vector;
uint64_t entry = s->ioredtbl[vector];
- if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) {
- level = !level;
- }
if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
IOAPIC_TRIGGER_LEVEL) {
/* level triggered */
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index c7f7b8406c..87fdb126cf 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -228,7 +228,7 @@ int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
encap.cap = KVM_CAP_IRQ_MPIC;
encap.args[0] = opp->fd;
- encap.args[1] = cs->cpu_index;
+ encap.args[1] = kvm_arch_vcpu_id(cs);
return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
}
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
new file mode 100644
index 0000000000..b2ef3e3f8e
--- /dev/null
+++ b/hw/intc/s390_flic.c
@@ -0,0 +1,322 @@
+/*
+ * QEMU S390x KVM floating interrupt controller (flic)
+ *
+ * Copyright 2014 IBM Corp.
+ * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include <sys/ioctl.h>
+#include "qemu/error-report.h"
+#include "hw/sysbus.h"
+#include "sysemu/kvm.h"
+#include "migration/qemu-file.h"
+#include "hw/s390x/s390_flic.h"
+#include "trace.h"
+
+#define FLIC_SAVE_INITIAL_SIZE getpagesize()
+#define FLIC_FAILED (-1UL)
+#define FLIC_SAVEVM_VERSION 1
+
+void s390_flic_init(void)
+{
+ DeviceState *dev;
+ int r;
+
+ if (kvm_enabled()) {
+ dev = qdev_create(NULL, "s390-flic");
+ object_property_add_child(qdev_get_machine(), "s390-flic",
+ OBJECT(dev), NULL);
+ r = qdev_init(dev);
+ if (r) {
+ error_report("flic: couldn't create qdev");
+ }
+ }
+}
+
+/**
+ * flic_get_all_irqs - store all pending irqs in buffer
+ * @buf: pointer to buffer which is passed to kernel
+ * @len: length of buffer
+ * @flic: pointer to flic device state
+ *
+ * Returns: -ENOMEM if buffer is too small,
+ * -EINVAL if attr.group is invalid,
+ * -EFAULT if copying to userspace failed,
+ * on success return number of stored interrupts
+ */
+static int flic_get_all_irqs(KVMS390FLICState *flic,
+ void *buf, int len)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_GET_ALL_IRQS,
+ .addr = (uint64_t) buf,
+ .attr = len,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
+
+ return rc == -1 ? -errno : rc;
+}
+
+static void flic_enable_pfault(KVMS390FLICState *flic)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_APF_ENABLE,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ if (rc) {
+ fprintf(stderr, "flic: couldn't enable pfault\n");
+ }
+}
+
+static void flic_disable_wait_pfault(KVMS390FLICState *flic)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ if (rc) {
+ fprintf(stderr, "flic: couldn't disable pfault\n");
+ }
+}
+
+/** flic_enqueue_irqs - returns 0 on success
+ * @buf: pointer to buffer which is passed to kernel
+ * @len: length of buffer
+ * @flic: pointer to flic device state
+ *
+ * Returns: -EINVAL if attr.group is unknown
+ */
+static int flic_enqueue_irqs(void *buf, uint64_t len,
+ KVMS390FLICState *flic)
+{
+ int rc;
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_ENQUEUE,
+ .addr = (uint64_t) buf,
+ .attr = len,
+ };
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ return rc ? -errno : 0;
+}
+
+/**
+ * __get_all_irqs - store all pending irqs in buffer
+ * @flic: pointer to flic device state
+ * @buf: pointer to pointer to a buffer
+ * @len: length of buffer
+ *
+ * Returns: return value of flic_get_all_irqs
+ * Note: Retry and increase buffer size until flic_get_all_irqs
+ * either returns a value >= 0 or a negative error code.
+ * -ENOMEM is an exception, which means the buffer is too small
+ * and we should try again. Other negative error codes can be
+ * -EFAULT and -EINVAL which we ignore at this point
+ */
+static int __get_all_irqs(KVMS390FLICState *flic,
+ void **buf, int len)
+{
+ int r;
+
+ do {
+ /* returns -ENOMEM if buffer is too small and number
+ * of queued interrupts on success */
+ r = flic_get_all_irqs(flic, *buf, len);
+ if (r >= 0) {
+ break;
+ }
+ len *= 2;
+ *buf = g_try_realloc(*buf, len);
+ if (!buf) {
+ return -ENOMEM;
+ }
+ } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
+
+ return r;
+}
+
+/**
+ * kvm_flic_save - Save pending floating interrupts
+ * @f: QEMUFile containing migration state
+ * @opaque: pointer to flic device state
+ *
+ * Note: Pass buf and len to kernel. Start with one page and
+ * increase until buffer is sufficient or maxium size is
+ * reached
+ */
+static void kvm_flic_save(QEMUFile *f, void *opaque)
+{
+ KVMS390FLICState *flic = opaque;
+ int len = FLIC_SAVE_INITIAL_SIZE;
+ void *buf;
+ int count;
+
+ flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
+
+ buf = g_try_malloc0(len);
+ if (!buf) {
+ /* Storing FLIC_FAILED into the count field here will cause the
+ * target system to fail when attempting to load irqs from the
+ * migration state */
+ error_report("flic: couldn't allocate memory");
+ qemu_put_be64(f, FLIC_FAILED);
+ return;
+ }
+
+ count = __get_all_irqs(flic, &buf, len);
+ if (count < 0) {
+ error_report("flic: couldn't retrieve irqs from kernel, rc %d",
+ count);
+ /* Storing FLIC_FAILED into the count field here will cause the
+ * target system to fail when attempting to load irqs from the
+ * migration state */
+ qemu_put_be64(f, FLIC_FAILED);
+ } else {
+ qemu_put_be64(f, count);
+ qemu_put_buffer(f, (uint8_t *) buf,
+ count * sizeof(struct kvm_s390_irq));
+ }
+ g_free(buf);
+}
+
+/**
+ * kvm_flic_load - Load pending floating interrupts
+ * @f: QEMUFile containing migration state
+ * @opaque: pointer to flic device state
+ * @version_id: version id for migration
+ *
+ * Returns: value of flic_enqueue_irqs, -EINVAL on error
+ * Note: Do nothing when no interrupts where stored
+ * in QEMUFile
+ */
+static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
+{
+ uint64_t len = 0;
+ uint64_t count = 0;
+ void *buf = NULL;
+ int r = 0;
+
+ if (version_id != FLIC_SAVEVM_VERSION) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ flic_enable_pfault((struct KVMS390FLICState *) opaque);
+
+ count = qemu_get_be64(f);
+ len = count * sizeof(struct kvm_s390_irq);
+ if (count == FLIC_FAILED) {
+ r = -EINVAL;
+ goto out;
+ }
+ if (count == 0) {
+ r = 0;
+ goto out;
+ }
+ buf = g_try_malloc0(len);
+ if (!buf) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
+ r = -EINVAL;
+ goto out_free;
+ }
+ r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
+
+out_free:
+ g_free(buf);
+out:
+ return r;
+}
+
+static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
+{
+ KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
+ struct kvm_create_device cd = {0};
+ int ret;
+
+ flic_state->fd = -1;
+ if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
+ trace_flic_no_device_api(errno);
+ return;
+ }
+
+ cd.type = KVM_DEV_TYPE_FLIC;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ trace_flic_create_device(errno);
+ return;
+ }
+ flic_state->fd = cd.fd;
+
+ /* Register savevm handler for floating interrupts */
+ register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
+ kvm_flic_load, (void *) flic_state);
+}
+
+static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
+{
+ KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
+
+ unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
+}
+
+static void kvm_s390_flic_reset(DeviceState *dev)
+{
+ KVMS390FLICState *flic = KVM_S390_FLIC(dev);
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_CLEAR_IRQS,
+ };
+ int rc = 0;
+
+ if (flic->fd == -1) {
+ return;
+ }
+
+ flic_disable_wait_pfault(flic);
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+ if (rc) {
+ trace_flic_reset_failed(errno);
+ }
+
+ flic_enable_pfault(flic);
+}
+
+static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = kvm_s390_flic_realize;
+ dc->unrealize = kvm_s390_flic_unrealize;
+ dc->reset = kvm_s390_flic_reset;
+}
+
+static const TypeInfo kvm_s390_flic_info = {
+ .name = TYPE_KVM_S390_FLIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMS390FLICState),
+ .class_init = kvm_s390_flic_class_init,
+};
+
+static void kvm_s390_flic_register_types(void)
+{
+ type_register_static(&kvm_s390_flic_info);
+}
+
+type_init(kvm_s390_flic_register_types)
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index b437563fb9..64aabe753d 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -33,6 +33,17 @@
#include "qemu/error-report.h"
#include "qapi/visitor.h"
+static int get_cpu_index_by_dt_id(int cpu_dt_id)
+{
+ PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
+
+ if (cpu) {
+ return cpu->parent_obj.cpu_index;
+ }
+
+ return -1;
+}
+
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
@@ -659,7 +670,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
- target_ulong server = args[0];
+ target_ulong server = get_cpu_index_by_dt_id(args[0]);
target_ulong mfrr = args[1];
if (server >= spapr->icp->nr_servers) {
@@ -728,7 +739,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
nr = rtas_ld(args, 0);
- server = rtas_ld(args, 1);
+ server = get_cpu_index_by_dt_id(rtas_ld(args, 1));
priority = rtas_ld(args, 2);
if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index c203646bd6..a5bbc2406d 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -65,7 +65,7 @@ static void icp_get_kvm_state(ICPState *ss)
ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to retrieve KVM interrupt controller state"
- " for CPU %d: %s", ss->cs->cpu_index, strerror(errno));
+ " for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno));
exit(1);
}
@@ -97,7 +97,7 @@ static int icp_set_kvm_state(ICPState *ss, int version_id)
ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to restore KVM interrupt controller state (0x%"
- PRIx64 ") for CPU %d: %s", state, ss->cs->cpu_index,
+ PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs),
strerror(errno));
return ret;
}
@@ -325,15 +325,15 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
struct kvm_enable_cap xics_enable_cap = {
.cap = KVM_CAP_IRQ_XICS,
.flags = 0,
- .args = {icpkvm->kernel_xics_fd, cs->cpu_index, 0, 0},
+ .args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
};
ss->cs = cs;
ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
if (ret < 0) {
- error_report("Unable to connect CPU%d to kernel XICS: %s",
- cs->cpu_index, strerror(errno));
+ error_report("Unable to connect CPU%ld to kernel XICS: %s",
+ kvm_arch_vcpu_id(cs), strerror(errno));
exit(1);
}
}
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
index ef4f3a84d7..a87ca6ddcc 100644
--- a/hw/moxie/moxiesim.c
+++ b/hw/moxie/moxiesim.c
@@ -55,7 +55,7 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
&entry, &kernel_low, &kernel_high, 1,
ELF_MACHINE, 0);
- if (!kernel_size) {
+ if (kernel_size <= 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loader_params->kernel_filename);
exit(1);
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 75e80c2c48..ea93293122 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -32,3 +32,6 @@ obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
obj-$(CONFIG_VIRTIO) += virtio-net.o
obj-y += vhost_net.o
+
+obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
+ fsl_etsec/rings.o fsl_etsec/miim.o
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
new file mode 100644
index 0000000000..d4b4429446
--- /dev/null
+++ b/hw/net/fsl_etsec/etsec.c
@@ -0,0 +1,465 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+
+/*
+ * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
+ */
+
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "hw/ptimer.h"
+#include "etsec.h"
+#include "registers.h"
+
+/* #define HEX_DUMP */
+/* #define DEBUG_REGISTER */
+
+#ifdef DEBUG_REGISTER
+static const int debug_etsec = 1;
+#else
+static const int debug_etsec;
+#endif
+
+#define DPRINTF(fmt, ...) do { \
+ if (debug_etsec) { \
+ qemu_log(fmt , ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
+{
+ eTSEC *etsec = opaque;
+ uint32_t reg_index = addr / 4;
+ eTSEC_Register *reg = NULL;
+ uint32_t ret = 0x0;
+
+ assert(reg_index < ETSEC_REG_NUMBER);
+
+ reg = &etsec->regs[reg_index];
+
+
+ switch (reg->access) {
+ case ACC_WO:
+ ret = 0x00000000;
+ break;
+
+ case ACC_RW:
+ case ACC_W1C:
+ case ACC_RO:
+ default:
+ ret = reg->value;
+ break;
+ }
+
+ DPRINTF("Read 0x%08x @ 0x" TARGET_FMT_plx
+ " : %s (%s)\n",
+ ret, addr, reg->name, reg->desc);
+
+ return ret;
+}
+
+static void write_tstat(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ int i = 0;
+
+ for (i = 0; i < 8; i++) {
+ /* Check THLTi flag in TSTAT */
+ if (value & (1 << (31 - i))) {
+ etsec_walk_tx_ring(etsec, i);
+ }
+ }
+
+ /* Write 1 to clear */
+ reg->value &= ~value;
+}
+
+static void write_rstat(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ int i = 0;
+
+ for (i = 0; i < 8; i++) {
+ /* Check QHLTi flag in RSTAT */
+ if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
+ etsec_walk_rx_ring(etsec, i);
+ }
+ }
+
+ /* Write 1 to clear */
+ reg->value &= ~value;
+}
+
+static void write_tbasex(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value & ~0x7;
+
+ /* Copy this value in the ring's TxBD pointer */
+ etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
+}
+
+static void write_rbasex(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value & ~0x7;
+
+ /* Copy this value in the ring's RxBD pointer */
+ etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
+}
+
+static void write_ievent(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ /* Write 1 to clear */
+ reg->value &= ~value;
+
+ if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
+ qemu_irq_lower(etsec->tx_irq);
+ }
+ if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
+ qemu_irq_lower(etsec->rx_irq);
+ }
+
+ if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
+ IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
+ IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
+ IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
+ IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
+ IEVENT_MMRW))) {
+ qemu_irq_lower(etsec->err_irq);
+ }
+}
+
+static void write_dmactrl(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value;
+
+ if (value & DMACTRL_GRS) {
+
+ if (etsec->rx_buffer_len != 0) {
+ /* Graceful receive stop delayed until end of frame */
+ } else {
+ /* Graceful receive stop now */
+ etsec->regs[IEVENT].value |= IEVENT_GRSC;
+ if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
+ qemu_irq_raise(etsec->err_irq);
+ }
+ }
+ }
+
+ if (value & DMACTRL_GTS) {
+
+ if (etsec->tx_buffer_len != 0) {
+ /* Graceful transmit stop delayed until end of frame */
+ } else {
+ /* Graceful transmit stop now */
+ etsec->regs[IEVENT].value |= IEVENT_GTSC;
+ if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
+ qemu_irq_raise(etsec->err_irq);
+ }
+ }
+ }
+
+ if (!(value & DMACTRL_WOP)) {
+ /* Start polling */
+ ptimer_stop(etsec->ptimer);
+ ptimer_set_count(etsec->ptimer, 1);
+ ptimer_run(etsec->ptimer, 1);
+ }
+}
+
+static void etsec_write(void *opaque,
+ hwaddr addr,
+ uint64_t value,
+ unsigned size)
+{
+ eTSEC *etsec = opaque;
+ uint32_t reg_index = addr / 4;
+ eTSEC_Register *reg = NULL;
+ uint32_t before = 0x0;
+
+ assert(reg_index < ETSEC_REG_NUMBER);
+
+ reg = &etsec->regs[reg_index];
+ before = reg->value;
+
+ switch (reg_index) {
+ case IEVENT:
+ write_ievent(etsec, reg, reg_index, value);
+ break;
+
+ case DMACTRL:
+ write_dmactrl(etsec, reg, reg_index, value);
+ break;
+
+ case TSTAT:
+ write_tstat(etsec, reg, reg_index, value);
+ break;
+
+ case RSTAT:
+ write_rstat(etsec, reg, reg_index, value);
+ break;
+
+ case TBASE0 ... TBASE7:
+ write_tbasex(etsec, reg, reg_index, value);
+ break;
+
+ case RBASE0 ... RBASE7:
+ write_rbasex(etsec, reg, reg_index, value);
+ break;
+
+ case MIIMCFG ... MIIMIND:
+ etsec_write_miim(etsec, reg, reg_index, value);
+ break;
+
+ default:
+ /* Default handling */
+ switch (reg->access) {
+
+ case ACC_RW:
+ case ACC_WO:
+ reg->value = value;
+ break;
+
+ case ACC_W1C:
+ reg->value &= ~value;
+ break;
+
+ case ACC_RO:
+ default:
+ /* Read Only or Unknown register */
+ break;
+ }
+ }
+
+ DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx
+ " val:0x%08x->0x%08x : %s (%s)\n",
+ (unsigned int)value, addr, before, reg->value,
+ reg->name, reg->desc);
+}
+
+static const MemoryRegionOps etsec_ops = {
+ .read = etsec_read,
+ .write = etsec_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void etsec_timer_hit(void *opaque)
+{
+ eTSEC *etsec = opaque;
+
+ ptimer_stop(etsec->ptimer);
+
+ if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
+
+ if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
+ etsec_walk_tx_ring(etsec, 0);
+ }
+ ptimer_set_count(etsec->ptimer, 1);
+ ptimer_run(etsec->ptimer, 1);
+ }
+}
+
+static void etsec_reset(DeviceState *d)
+{
+ eTSEC *etsec = ETSEC_COMMON(d);
+ int i = 0;
+ int reg_index = 0;
+
+ /* Default value for all registers */
+ for (i = 0; i < ETSEC_REG_NUMBER; i++) {
+ etsec->regs[i].name = "Reserved";
+ etsec->regs[i].desc = "";
+ etsec->regs[i].access = ACC_UNKNOWN;
+ etsec->regs[i].value = 0x00000000;
+ }
+
+ /* Set-up known registers */
+ for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
+
+ reg_index = eTSEC_registers_def[i].offset / 4;
+
+ etsec->regs[reg_index].name = eTSEC_registers_def[i].name;
+ etsec->regs[reg_index].desc = eTSEC_registers_def[i].desc;
+ etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
+ etsec->regs[reg_index].value = eTSEC_registers_def[i].reset;
+ }
+
+ etsec->tx_buffer = NULL;
+ etsec->tx_buffer_len = 0;
+ etsec->rx_buffer = NULL;
+ etsec->rx_buffer_len = 0;
+
+ etsec->phy_status =
+ MII_SR_EXTENDED_CAPS | MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
+ MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
+ MII_SR_EXTENDED_STATUS | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
+ MII_SR_10T_HD_CAPS | MII_SR_10T_FD_CAPS | MII_SR_100X_HD_CAPS |
+ MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
+}
+
+static void etsec_cleanup(NetClientState *nc)
+{
+ /* qemu_log("eTSEC cleanup\n"); */
+}
+
+static int etsec_can_receive(NetClientState *nc)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+ return etsec->rx_buffer_len == 0;
+}
+
+static ssize_t etsec_receive(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+#if defined(HEX_DUMP)
+ fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
+ qemu_hexdump(buf, stderr, "", size);
+#endif
+ etsec_rx_ring_write(etsec, buf, size);
+ return size;
+}
+
+
+static void etsec_set_link_status(NetClientState *nc)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+ etsec_miim_link_status(etsec, nc);
+}
+
+static NetClientInfo net_etsec_info = {
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .size = sizeof(NICState),
+ .can_receive = etsec_can_receive,
+ .receive = etsec_receive,
+ .cleanup = etsec_cleanup,
+ .link_status_changed = etsec_set_link_status,
+};
+
+static void etsec_realize(DeviceState *dev, Error **errp)
+{
+ eTSEC *etsec = ETSEC_COMMON(dev);
+
+ etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
+ object_get_typename(OBJECT(dev)), dev->id, etsec);
+ qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
+
+
+ etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
+ etsec->ptimer = ptimer_init(etsec->bh);
+ ptimer_set_freq(etsec->ptimer, 100);
+}
+
+static void etsec_instance_init(Object *obj)
+{
+ eTSEC *etsec = ETSEC_COMMON(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
+ "eTSEC", 0x1000);
+ sysbus_init_mmio(sbd, &etsec->io_area);
+
+ sysbus_init_irq(sbd, &etsec->tx_irq);
+ sysbus_init_irq(sbd, &etsec->rx_irq);
+ sysbus_init_irq(sbd, &etsec->err_irq);
+}
+
+static Property etsec_properties[] = {
+ DEFINE_NIC_PROPERTIES(eTSEC, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etsec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = etsec_realize;
+ dc->reset = etsec_reset;
+ dc->props = etsec_properties;
+}
+
+static TypeInfo etsec_info = {
+ .name = "eTSEC",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(eTSEC),
+ .class_init = etsec_class_init,
+ .instance_init = etsec_instance_init,
+};
+
+static void etsec_register_types(void)
+{
+ type_register_static(&etsec_info);
+}
+
+type_init(etsec_register_types)
+
+DeviceState *etsec_create(hwaddr base,
+ MemoryRegion * mr,
+ NICInfo * nd,
+ qemu_irq tx_irq,
+ qemu_irq rx_irq,
+ qemu_irq err_irq)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "eTSEC");
+ qdev_set_nic_properties(dev, nd);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
+
+ memory_region_add_subregion(mr, base,
+ SYS_BUS_DEVICE(dev)->mmio[0].memory);
+
+ return dev;
+}
diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h
new file mode 100644
index 0000000000..78d2c57ed3
--- /dev/null
+++ b/hw/net/fsl_etsec/etsec.h
@@ -0,0 +1,174 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+#ifndef _ETSEC_H_
+#define _ETSEC_H_
+
+#include "hw/qdev.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/ptimer.h"
+
+/* Buffer Descriptors */
+
+typedef struct eTSEC_rxtx_bd {
+ uint16_t flags;
+ uint16_t length;
+ uint32_t bufptr;
+} eTSEC_rxtx_bd;
+
+#define BD_WRAP (1 << 13)
+#define BD_INTERRUPT (1 << 12)
+#define BD_LAST (1 << 11)
+
+#define BD_TX_READY (1 << 15)
+#define BD_TX_PADCRC (1 << 14)
+#define BD_TX_TC (1 << 10)
+#define BD_TX_PREDEF (1 << 9)
+#define BD_TX_HFELC (1 << 7)
+#define BD_TX_CFRL (1 << 6)
+#define BD_TX_RC_MASK 0xF
+#define BD_TX_RC_OFFSET 0x2
+#define BD_TX_TOEUN (1 << 1)
+#define BD_TX_TR (1 << 0)
+
+#define BD_RX_EMPTY (1 << 15)
+#define BD_RX_RO1 (1 << 14)
+#define BD_RX_FIRST (1 << 10)
+#define BD_RX_MISS (1 << 8)
+#define BD_RX_BROADCAST (1 << 7)
+#define BD_RX_MULTICAST (1 << 6)
+#define BD_RX_LG (1 << 5)
+#define BD_RX_NO (1 << 4)
+#define BD_RX_SH (1 << 3)
+#define BD_RX_CR (1 << 2)
+#define BD_RX_OV (1 << 1)
+#define BD_RX_TR (1 << 0)
+
+/* Tx FCB flags */
+#define FCB_TX_VLN (1 << 7)
+#define FCB_TX_IP (1 << 6)
+#define FCB_TX_IP6 (1 << 5)
+#define FCB_TX_TUP (1 << 4)
+#define FCB_TX_UDP (1 << 3)
+#define FCB_TX_CIP (1 << 2)
+#define FCB_TX_CTU (1 << 1)
+#define FCB_TX_NPH (1 << 0)
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* eTSEC */
+
+/* Number of register in the device */
+#define ETSEC_REG_NUMBER 1024
+
+typedef struct eTSEC_Register {
+ const char *name;
+ const char *desc;
+ uint32_t access;
+ uint32_t value;
+} eTSEC_Register;
+
+typedef struct eTSEC {
+ SysBusDevice busdev;
+
+ MemoryRegion io_area;
+
+ eTSEC_Register regs[ETSEC_REG_NUMBER];
+
+ NICState *nic;
+ NICConf conf;
+
+ /* Tx */
+
+ uint8_t *tx_buffer;
+ uint32_t tx_buffer_len;
+ eTSEC_rxtx_bd first_bd;
+
+ /* Rx */
+
+ uint8_t *rx_buffer;
+ uint32_t rx_buffer_len;
+ uint32_t rx_remaining_data;
+ uint8_t rx_first_in_frame;
+ uint8_t rx_fcb_size;
+ eTSEC_rxtx_bd rx_first_bd;
+ uint8_t rx_fcb[10];
+ uint32_t rx_padding;
+
+ /* IRQs */
+ qemu_irq tx_irq;
+ qemu_irq rx_irq;
+ qemu_irq err_irq;
+
+
+ uint16_t phy_status;
+ uint16_t phy_control;
+
+ /* Polling */
+ QEMUBH *bh;
+ struct ptimer_state *ptimer;
+
+} eTSEC;
+
+#define TYPE_ETSEC_COMMON "eTSEC"
+#define ETSEC_COMMON(obj) \
+ OBJECT_CHECK(eTSEC, (obj), TYPE_ETSEC_COMMON)
+
+#define eTSEC_TRANSMIT 1
+#define eTSEC_RECEIVE 2
+
+DeviceState *etsec_create(hwaddr base,
+ MemoryRegion *mr,
+ NICInfo *nd,
+ qemu_irq tx_irq,
+ qemu_irq rx_irq,
+ qemu_irq err_irq);
+
+void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
+void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
+void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
+
+void etsec_write_miim(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value);
+
+void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc);
+
+#endif /* ! _ETSEC_H_ */
diff --git a/hw/net/fsl_etsec/miim.c b/hw/net/fsl_etsec/miim.c
new file mode 100644
index 0000000000..1931b74e6c
--- /dev/null
+++ b/hw/net/fsl_etsec/miim.c
@@ -0,0 +1,146 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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 "etsec.h"
+#include "registers.h"
+
+/* #define DEBUG_MIIM */
+
+#define MIIM_CONTROL 0
+#define MIIM_STATUS 1
+#define MIIM_PHY_ID_1 2
+#define MIIM_PHY_ID_2 3
+#define MIIM_T2_STATUS 10
+#define MIIM_EXT_STATUS 15
+
+static void miim_read_cycle(eTSEC *etsec)
+{
+ uint8_t phy;
+ uint8_t addr;
+ uint16_t value;
+
+ phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
+ (void)phy; /* Unreferenced */
+ addr = etsec->regs[MIIMADD].value & 0x1F;
+
+ switch (addr) {
+ case MIIM_CONTROL:
+ value = etsec->phy_control;
+ break;
+ case MIIM_STATUS:
+ value = etsec->phy_status;
+ break;
+ case MIIM_T2_STATUS:
+ value = 0x1800; /* Local and remote receivers OK */
+ break;
+ default:
+ value = 0x0;
+ break;
+ };
+
+#ifdef DEBUG_MIIM
+ qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
+#endif
+
+ etsec->regs[MIIMSTAT].value = value;
+}
+
+static void miim_write_cycle(eTSEC *etsec)
+{
+ uint8_t phy;
+ uint8_t addr;
+ uint16_t value;
+
+ phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
+ (void)phy; /* Unreferenced */
+ addr = etsec->regs[MIIMADD].value & 0x1F;
+ value = etsec->regs[MIIMCON].value & 0xffff;
+
+#ifdef DEBUG_MIIM
+ qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
+#endif
+
+ switch (addr) {
+ case MIIM_CONTROL:
+ etsec->phy_control = value & ~(0x8100);
+ break;
+ default:
+ break;
+ };
+}
+
+void etsec_write_miim(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+
+ switch (reg_index) {
+
+ case MIIMCOM:
+ /* Read and scan cycle */
+
+ if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
+ /* Read */
+ miim_read_cycle(etsec);
+ }
+ reg->value = value;
+ break;
+
+ case MIIMCON:
+ reg->value = value & 0xffff;
+ miim_write_cycle(etsec);
+ break;
+
+ default:
+ /* Default handling */
+ switch (reg->access) {
+
+ case ACC_RW:
+ case ACC_WO:
+ reg->value = value;
+ break;
+
+ case ACC_W1C:
+ reg->value &= ~value;
+ break;
+
+ case ACC_RO:
+ default:
+ /* Read Only or Unknown register */
+ break;
+ }
+ }
+
+}
+
+void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
+{
+ /* Set link status */
+ if (nc->link_down) {
+ etsec->phy_status &= ~MII_SR_LINK_STATUS;
+ } else {
+ etsec->phy_status |= MII_SR_LINK_STATUS;
+ }
+}
diff --git a/hw/net/fsl_etsec/registers.c b/hw/net/fsl_etsec/registers.c
new file mode 100644
index 0000000000..a7bbfa113f
--- /dev/null
+++ b/hw/net/fsl_etsec/registers.c
@@ -0,0 +1,295 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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 "registers.h"
+
+const eTSEC_Register_Definition eTSEC_registers_def[] = {
+{0x000, "TSEC_ID", "Controller ID register", ACC_RO, 0x01240000},
+{0x004, "TSEC_ID2", "Controller ID register 2", ACC_RO, 0x003000F0},
+{0x010, "IEVENT", "Interrupt event register", ACC_W1C, 0x00000000},
+{0x014, "IMASK", "Interrupt mask register", ACC_RW, 0x00000000},
+{0x018, "EDIS", "Error disabled register", ACC_RW, 0x00000000},
+{0x020, "ECNTRL", "Ethernet control register", ACC_RW, 0x00000040},
+{0x028, "PTV", "Pause time value register", ACC_RW, 0x00000000},
+{0x02C, "DMACTRL", "DMA control register", ACC_RW, 0x00000000},
+{0x030, "TBIPA", "TBI PHY address register", ACC_RW, 0x00000000},
+
+/* eTSEC FIFO Control and Status Registers */
+
+{0x058, "FIFO_RX_ALARM", "FIFO receive alarm start threshold register", ACC_RW, 0x00000040},
+{0x05C, "FIFO_RX_ALARM_SHUTOFF", "FIFO receive alarm shut-off threshold register", ACC_RW, 0x00000080},
+{0x08C, "FIFO_TX_THR", "FIFO transmit threshold register", ACC_RW, 0x00000080},
+{0x098, "FIFO_TX_STARVE", "FIFO transmit starve register", ACC_RW, 0x00000040},
+{0x09C, "FIFO_TX_STARVE_SHUTOFF", "FIFO transmit starve shut-off register", ACC_RW, 0x00000080},
+
+/* eTSEC Transmit Control and Status Registers */
+
+{0x100, "TCTRL", "Transmit control register", ACC_RW, 0x00000000},
+{0x104, "TSTAT", "Transmit status register", ACC_W1C, 0x00000000},
+{0x108, "DFVLAN", "Default VLAN control word", ACC_RW, 0x81000000},
+{0x110, "TXIC", "Transmit interrupt coalescing register", ACC_RW, 0x00000000},
+{0x114, "TQUEUE", "Transmit queue control register", ACC_RW, 0x00008000},
+{0x140, "TR03WT", "TxBD Rings 0-3 round-robin weightings", ACC_RW, 0x00000000},
+{0x144, "TR47WT", "TxBD Rings 4-7 round-robin weightings", ACC_RW, 0x00000000},
+{0x180, "TBDBPH", "Tx data buffer pointer high bits", ACC_RW, 0x00000000},
+{0x184, "TBPTR0", "TxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0x18C, "TBPTR1", "TxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0x194, "TBPTR2", "TxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0x19C, "TBPTR3", "TxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0x1A4, "TBPTR4", "TxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0x1AC, "TBPTR5", "TxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0x1B4, "TBPTR6", "TxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0x1BC, "TBPTR7", "TxBD pointer for ring 7", ACC_RW, 0x00000000},
+{0x200, "TBASEH", "TxBD base address high bits", ACC_RW, 0x00000000},
+{0x204, "TBASE0", "TxBD base address of ring 0", ACC_RW, 0x00000000},
+{0x20C, "TBASE1", "TxBD base address of ring 1", ACC_RW, 0x00000000},
+{0x214, "TBASE2", "TxBD base address of ring 2", ACC_RW, 0x00000000},
+{0x21C, "TBASE3", "TxBD base address of ring 3", ACC_RW, 0x00000000},
+{0x224, "TBASE4", "TxBD base address of ring 4", ACC_RW, 0x00000000},
+{0x22C, "TBASE5", "TxBD base address of ring 5", ACC_RW, 0x00000000},
+{0x234, "TBASE6", "TxBD base address of ring 6", ACC_RW, 0x00000000},
+{0x23C, "TBASE7", "TxBD base address of ring 7", ACC_RW, 0x00000000},
+{0x280, "TMR_TXTS1_ID", "Tx time stamp identification tag (set 1)", ACC_RO, 0x00000000},
+{0x284, "TMR_TXTS2_ID", "Tx time stamp identification tag (set 2)", ACC_RO, 0x00000000},
+{0x2C0, "TMR_TXTS1_H", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
+{0x2C4, "TMR_TXTS1_L", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
+{0x2C8, "TMR_TXTS2_H", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
+{0x2CC, "TMR_TXTS2_L", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
+
+/* eTSEC Receive Control and Status Registers */
+
+{0x300, "RCTRL", "Receive control register", ACC_RW, 0x00000000},
+{0x304, "RSTAT", "Receive status register", ACC_W1C, 0x00000000},
+{0x310, "RXIC", "Receive interrupt coalescing register", ACC_RW, 0x00000000},
+{0x314, "RQUEUE", "Receive queue control register.", ACC_RW, 0x00800080},
+{0x330, "RBIFX", "Receive bit field extract control register", ACC_RW, 0x00000000},
+{0x334, "RQFAR", "Receive queue filing table address register", ACC_RW, 0x00000000},
+{0x338, "RQFCR", "Receive queue filing table control register", ACC_RW, 0x00000000},
+{0x33C, "RQFPR", "Receive queue filing table property register", ACC_RW, 0x00000000},
+{0x340, "MRBLR", "Maximum receive buffer length register", ACC_RW, 0x00000000},
+{0x380, "RBDBPH", "Rx data buffer pointer high bits", ACC_RW, 0x00000000},
+{0x384, "RBPTR0", "RxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0x38C, "RBPTR1", "RxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0x394, "RBPTR2", "RxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0x39C, "RBPTR3", "RxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0x3A4, "RBPTR4", "RxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0x3AC, "RBPTR5", "RxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0x3B4, "RBPTR6", "RxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0x3BC, "RBPTR7", "RxBD pointer for ring 7", ACC_RW, 0x00000000},
+{0x400, "RBASEH", "RxBD base address high bits", ACC_RW, 0x00000000},
+{0x404, "RBASE0", "RxBD base address of ring 0", ACC_RW, 0x00000000},
+{0x40C, "RBASE1", "RxBD base address of ring 1", ACC_RW, 0x00000000},
+{0x414, "RBASE2", "RxBD base address of ring 2", ACC_RW, 0x00000000},
+{0x41C, "RBASE3", "RxBD base address of ring 3", ACC_RW, 0x00000000},
+{0x424, "RBASE4", "RxBD base address of ring 4", ACC_RW, 0x00000000},
+{0x42C, "RBASE5", "RxBD base address of ring 5", ACC_RW, 0x00000000},
+{0x434, "RBASE6", "RxBD base address of ring 6", ACC_RW, 0x00000000},
+{0x43C, "RBASE7", "RxBD base address of ring 7", ACC_RW, 0x00000000},
+{0x4C0, "TMR_RXTS_H", "Rx timer time stamp register high", ACC_RW, 0x00000000},
+{0x4C4, "TMR_RXTS_L", "Rx timer time stamp register low", ACC_RW, 0x00000000},
+
+/* eTSEC MAC Registers */
+
+{0x500, "MACCFG1", "MAC configuration register 1", ACC_RW, 0x00000000},
+{0x504, "MACCFG2", "MAC configuration register 2", ACC_RW, 0x00007000},
+{0x508, "IPGIFG", "Inter-packet/inter-frame gap register", ACC_RW, 0x40605060},
+{0x50C, "HAFDUP", "Half-duplex control", ACC_RW, 0x00A1F037},
+{0x510, "MAXFRM", "Maximum frame length", ACC_RW, 0x00000600},
+{0x520, "MIIMCFG", "MII management configuration", ACC_RW, 0x00000007},
+{0x524, "MIIMCOM", "MII management command", ACC_RW, 0x00000000},
+{0x528, "MIIMADD", "MII management address", ACC_RW, 0x00000000},
+{0x52C, "MIIMCON", "MII management control", ACC_WO, 0x00000000},
+{0x530, "MIIMSTAT", "MII management status", ACC_RO, 0x00000000},
+{0x534, "MIIMIND", "MII management indicator", ACC_RO, 0x00000000},
+{0x53C, "IFSTAT", "Interface status", ACC_RO, 0x00000000},
+{0x540, "MACSTNADDR1", "MAC station address register 1", ACC_RW, 0x00000000},
+{0x544, "MACSTNADDR2", "MAC station address register 2", ACC_RW, 0x00000000},
+{0x548, "MAC01ADDR1", "MAC exact match address 1, part 1", ACC_RW, 0x00000000},
+{0x54C, "MAC01ADDR2", "MAC exact match address 1, part 2", ACC_RW, 0x00000000},
+{0x550, "MAC02ADDR1", "MAC exact match address 2, part 1", ACC_RW, 0x00000000},
+{0x554, "MAC02ADDR2", "MAC exact match address 2, part 2", ACC_RW, 0x00000000},
+{0x558, "MAC03ADDR1", "MAC exact match address 3, part 1", ACC_RW, 0x00000000},
+{0x55C, "MAC03ADDR2", "MAC exact match address 3, part 2", ACC_RW, 0x00000000},
+{0x560, "MAC04ADDR1", "MAC exact match address 4, part 1", ACC_RW, 0x00000000},
+{0x564, "MAC04ADDR2", "MAC exact match address 4, part 2", ACC_RW, 0x00000000},
+{0x568, "MAC05ADDR1", "MAC exact match address 5, part 1", ACC_RW, 0x00000000},
+{0x56C, "MAC05ADDR2", "MAC exact match address 5, part 2", ACC_RW, 0x00000000},
+{0x570, "MAC06ADDR1", "MAC exact match address 6, part 1", ACC_RW, 0x00000000},
+{0x574, "MAC06ADDR2", "MAC exact match address 6, part 2", ACC_RW, 0x00000000},
+{0x578, "MAC07ADDR1", "MAC exact match address 7, part 1", ACC_RW, 0x00000000},
+{0x57C, "MAC07ADDR2", "MAC exact match address 7, part 2", ACC_RW, 0x00000000},
+{0x580, "MAC08ADDR1", "MAC exact match address 8, part 1", ACC_RW, 0x00000000},
+{0x584, "MAC08ADDR2", "MAC exact match address 8, part 2", ACC_RW, 0x00000000},
+{0x588, "MAC09ADDR1", "MAC exact match address 9, part 1", ACC_RW, 0x00000000},
+{0x58C, "MAC09ADDR2", "MAC exact match address 9, part 2", ACC_RW, 0x00000000},
+{0x590, "MAC10ADDR1", "MAC exact match address 10, part 1", ACC_RW, 0x00000000},
+{0x594, "MAC10ADDR2", "MAC exact match address 10, part 2", ACC_RW, 0x00000000},
+{0x598, "MAC11ADDR1", "MAC exact match address 11, part 1", ACC_RW, 0x00000000},
+{0x59C, "MAC11ADDR2", "MAC exact match address 11, part 2", ACC_RW, 0x00000000},
+{0x5A0, "MAC12ADDR1", "MAC exact match address 12, part 1", ACC_RW, 0x00000000},
+{0x5A4, "MAC12ADDR2", "MAC exact match address 12, part 2", ACC_RW, 0x00000000},
+{0x5A8, "MAC13ADDR1", "MAC exact match address 13, part 1", ACC_RW, 0x00000000},
+{0x5AC, "MAC13ADDR2", "MAC exact match address 13, part 2", ACC_RW, 0x00000000},
+{0x5B0, "MAC14ADDR1", "MAC exact match address 14, part 1", ACC_RW, 0x00000000},
+{0x5B4, "MAC14ADDR2", "MAC exact match address 14, part 2", ACC_RW, 0x00000000},
+{0x5B8, "MAC15ADDR1", "MAC exact match address 15, part 1", ACC_RW, 0x00000000},
+{0x5BC, "MAC15ADDR2", "MAC exact match address 15, part 2", ACC_RW, 0x00000000},
+
+/* eTSEC, "Transmit", "and", Receive, Counters */
+
+{0x680, "TR64", "Transmit and receive 64-byte frame counter ", ACC_RW, 0x00000000},
+{0x684, "TR127", "Transmit and receive 65- to 127-byte frame counter", ACC_RW, 0x00000000},
+{0x688, "TR255", "Transmit and receive 128- to 255-byte frame counter", ACC_RW, 0x00000000},
+{0x68C, "TR511", "Transmit and receive 256- to 511-byte frame counter", ACC_RW, 0x00000000},
+{0x690, "TR1K", "Transmit and receive 512- to 1023-byte frame counter", ACC_RW, 0x00000000},
+{0x694, "TRMAX", "Transmit and receive 1024- to 1518-byte frame counter", ACC_RW, 0x00000000},
+{0x698, "TRMGV", "Transmit and receive 1519- to 1522-byte good VLAN frame count", ACC_RW, 0x00000000},
+
+/* eTSEC Receive Counters */
+
+{0x69C, "RBYT", "Receive byte counter", ACC_RW, 0x00000000},
+{0x6A0, "RPKT", "Receive packet counter", ACC_RW, 0x00000000},
+{0x6A4, "RFCS", "Receive FCS error counter", ACC_RW, 0x00000000},
+{0x6A8, "RMCA", "Receive multicast packet counter", ACC_RW, 0x00000000},
+{0x6AC, "RBCA", "Receive broadcast packet counter", ACC_RW, 0x00000000},
+{0x6B0, "RXCF", "Receive control frame packet counter ", ACC_RW, 0x00000000},
+{0x6B4, "RXPF", "Receive PAUSE frame packet counter", ACC_RW, 0x00000000},
+{0x6B8, "RXUO", "Receive unknown OP code counter ", ACC_RW, 0x00000000},
+{0x6BC, "RALN", "Receive alignment error counter ", ACC_RW, 0x00000000},
+{0x6C0, "RFLR", "Receive frame length error counter ", ACC_RW, 0x00000000},
+{0x6C4, "RCDE", "Receive code error counter ", ACC_RW, 0x00000000},
+{0x6C8, "RCSE", "Receive carrier sense error counter", ACC_RW, 0x00000000},
+{0x6CC, "RUND", "Receive undersize packet counter", ACC_RW, 0x00000000},
+{0x6D0, "ROVR", "Receive oversize packet counter ", ACC_RW, 0x00000000},
+{0x6D4, "RFRG", "Receive fragments counter", ACC_RW, 0x00000000},
+{0x6D8, "RJBR", "Receive jabber counter ", ACC_RW, 0x00000000},
+{0x6DC, "RDRP", "Receive drop counter", ACC_RW, 0x00000000},
+
+/* eTSEC Transmit Counters */
+
+{0x6E0, "TBYT", "Transmit byte counter", ACC_RW, 0x00000000},
+{0x6E4, "TPKT", "Transmit packet counter", ACC_RW, 0x00000000},
+{0x6E8, "TMCA", "Transmit multicast packet counter ", ACC_RW, 0x00000000},
+{0x6EC, "TBCA", "Transmit broadcast packet counter ", ACC_RW, 0x00000000},
+{0x6F0, "TXPF", "Transmit PAUSE control frame counter ", ACC_RW, 0x00000000},
+{0x6F4, "TDFR", "Transmit deferral packet counter ", ACC_RW, 0x00000000},
+{0x6F8, "TEDF", "Transmit excessive deferral packet counter ", ACC_RW, 0x00000000},
+{0x6FC, "TSCL", "Transmit single collision packet counter", ACC_RW, 0x00000000},
+{0x700, "TMCL", "Transmit multiple collision packet counter", ACC_RW, 0x00000000},
+{0x704, "TLCL", "Transmit late collision packet counter", ACC_RW, 0x00000000},
+{0x708, "TXCL", "Transmit excessive collision packet counter", ACC_RW, 0x00000000},
+{0x70C, "TNCL", "Transmit total collision counter ", ACC_RW, 0x00000000},
+{0x714, "TDRP", "Transmit drop frame counter", ACC_RW, 0x00000000},
+{0x718, "TJBR", "Transmit jabber frame counter ", ACC_RW, 0x00000000},
+{0x71C, "TFCS", "Transmit FCS error counter", ACC_RW, 0x00000000},
+{0x720, "TXCF", "Transmit control frame counter ", ACC_RW, 0x00000000},
+{0x724, "TOVR", "Transmit oversize frame counter", ACC_RW, 0x00000000},
+{0x728, "TUND", "Transmit undersize frame counter ", ACC_RW, 0x00000000},
+{0x72C, "TFRG", "Transmit fragments frame counter ", ACC_RW, 0x00000000},
+
+/* eTSEC Counter Control and TOE Statistics Registers */
+
+{0x730, "CAR1", "Carry register one register", ACC_W1C, 0x00000000},
+{0x734, "CAR2", "Carry register two register ", ACC_W1C, 0x00000000},
+{0x738, "CAM1", "Carry register one mask register ", ACC_RW, 0xFE03FFFF},
+{0x73C, "CAM2", "Carry register two mask register ", ACC_RW, 0x000FFFFD},
+{0x740, "RREJ", "Receive filer rejected packet counter", ACC_RW, 0x00000000},
+
+/* Hash Function Registers */
+
+{0x800, "IGADDR0", "Individual/group address register 0", ACC_RW, 0x00000000},
+{0x804, "IGADDR1", "Individual/group address register 1", ACC_RW, 0x00000000},
+{0x808, "IGADDR2", "Individual/group address register 2", ACC_RW, 0x00000000},
+{0x80C, "IGADDR3", "Individual/group address register 3", ACC_RW, 0x00000000},
+{0x810, "IGADDR4", "Individual/group address register 4", ACC_RW, 0x00000000},
+{0x814, "IGADDR5", "Individual/group address register 5", ACC_RW, 0x00000000},
+{0x818, "IGADDR6", "Individual/group address register 6", ACC_RW, 0x00000000},
+{0x81C, "IGADDR7", "Individual/group address register 7", ACC_RW, 0x00000000},
+{0x880, "GADDR0", "Group address register 0", ACC_RW, 0x00000000},
+{0x884, "GADDR1", "Group address register 1", ACC_RW, 0x00000000},
+{0x888, "GADDR2", "Group address register 2", ACC_RW, 0x00000000},
+{0x88C, "GADDR3", "Group address register 3", ACC_RW, 0x00000000},
+{0x890, "GADDR4", "Group address register 4", ACC_RW, 0x00000000},
+{0x894, "GADDR5", "Group address register 5", ACC_RW, 0x00000000},
+{0x898, "GADDR6", "Group address register 6", ACC_RW, 0x00000000},
+{0x89C, "GADDR7", "Group address register 7", ACC_RW, 0x00000000},
+
+/* eTSEC DMA Attribute Registers */
+
+{0xBF8, "ATTR", "Attribute register", ACC_RW, 0x00000000},
+{0xBFC, "ATTRELI", "Attribute extract length and extract index register", ACC_RW, 0x00000000},
+
+
+/* eTSEC Lossless Flow Control Registers */
+
+{0xC00, "RQPRM0", "Receive Queue Parameters register 0 ", ACC_RW, 0x00000000},
+{0xC04, "RQPRM1", "Receive Queue Parameters register 1 ", ACC_RW, 0x00000000},
+{0xC08, "RQPRM2", "Receive Queue Parameters register 2 ", ACC_RW, 0x00000000},
+{0xC0C, "RQPRM3", "Receive Queue Parameters register 3 ", ACC_RW, 0x00000000},
+{0xC10, "RQPRM4", "Receive Queue Parameters register 4 ", ACC_RW, 0x00000000},
+{0xC14, "RQPRM5", "Receive Queue Parameters register 5 ", ACC_RW, 0x00000000},
+{0xC18, "RQPRM6", "Receive Queue Parameters register 6 ", ACC_RW, 0x00000000},
+{0xC1C, "RQPRM7", "Receive Queue Parameters register 7 ", ACC_RW, 0x00000000},
+{0xC44, "RFBPTR0", "Last Free RxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0xC4C, "RFBPTR1", "Last Free RxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0xC54, "RFBPTR2", "Last Free RxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0xC5C, "RFBPTR3", "Last Free RxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0xC64, "RFBPTR4", "Last Free RxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0xC6C, "RFBPTR5", "Last Free RxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0xC74, "RFBPTR6", "Last Free RxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0xC7C, "RFBPTR7", "Last Free RxBD pointer for ring 7", ACC_RW, 0x00000000},
+
+/* eTSEC Future Expansion Space */
+
+/* Reserved*/
+
+/* eTSEC IEEE 1588 Registers */
+
+{0xE00, "TMR_CTRL", "Timer control register", ACC_RW, 0x00010001},
+{0xE04, "TMR_TEVENT", "time stamp event register", ACC_W1C, 0x00000000},
+{0xE08, "TMR_TEMASK", "Timer event mask register", ACC_RW, 0x00000000},
+{0xE0C, "TMR_PEVENT", "time stamp event register", ACC_RW, 0x00000000},
+{0xE10, "TMR_PEMASK", "Timer event mask register", ACC_RW, 0x00000000},
+{0xE14, "TMR_STAT", "time stamp status register", ACC_RW, 0x00000000},
+{0xE18, "TMR_CNT_H", "timer counter high register", ACC_RW, 0x00000000},
+{0xE1C, "TMR_CNT_L", "timer counter low register", ACC_RW, 0x00000000},
+{0xE20, "TMR_ADD", "Timer drift compensation addend register", ACC_RW, 0x00000000},
+{0xE24, "TMR_ACC", "Timer accumulator register", ACC_RW, 0x00000000},
+{0xE28, "TMR_PRSC", "Timer prescale", ACC_RW, 0x00000002},
+{0xE30, "TMROFF_H", "Timer offset high", ACC_RW, 0x00000000},
+{0xE34, "TMROFF_L", "Timer offset low", ACC_RW, 0x00000000},
+{0xE40, "TMR_ALARM1_H", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
+{0xE44, "TMR_ALARM1_L", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
+{0xE48, "TMR_ALARM2_H", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
+{0xE4C, "TMR_ALARM2_L", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
+{0xE80, "TMR_FIPER1", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xE84, "TMR_FIPER2", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xE88, "TMR_FIPER3", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xEA0, "TMR_ETTS1_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
+{0xEA4, "TMR_ETTS1_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
+{0xEA8, "TMR_ETTS2_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
+{0xEAC, "TMR_ETTS2_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
+
+/* End Of Table */
+{0x0, 0x0, 0x0, 0x0, 0x0}
+};
diff --git a/hw/net/fsl_etsec/registers.h b/hw/net/fsl_etsec/registers.h
new file mode 100644
index 0000000000..7ad7686470
--- /dev/null
+++ b/hw/net/fsl_etsec/registers.h
@@ -0,0 +1,320 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+#ifndef _ETSEC_REGISTERS_H_
+#define _ETSEC_REGISTERS_H_
+
+#include <stdint.h>
+
+enum eTSEC_Register_Access_Type {
+ ACC_RW = 1, /* Read/Write */
+ ACC_RO = 2, /* Read Only */
+ ACC_WO = 3, /* Write Only */
+ ACC_W1C = 4, /* Write 1 to clear */
+ ACC_UNKNOWN = 5 /* Unknown register*/
+};
+
+typedef struct eTSEC_Register_Definition {
+ uint32_t offset;
+ const char *name;
+ const char *desc;
+ enum eTSEC_Register_Access_Type access;
+ uint32_t reset;
+} eTSEC_Register_Definition;
+
+extern const eTSEC_Register_Definition eTSEC_registers_def[];
+
+#define DMACTRL_LE (1 << 15)
+#define DMACTRL_GRS (1 << 4)
+#define DMACTRL_GTS (1 << 3)
+#define DMACTRL_WOP (1 << 0)
+
+#define IEVENT_PERR (1 << 0)
+#define IEVENT_DPE (1 << 1)
+#define IEVENT_FIQ (1 << 2)
+#define IEVENT_FIR (1 << 3)
+#define IEVENT_FGPI (1 << 4)
+#define IEVENT_RXF (1 << 7)
+#define IEVENT_GRSC (1 << 8)
+#define IEVENT_MMRW (1 << 9)
+#define IEVENT_MMRD (1 << 10)
+#define IEVENT_MAG (1 << 11)
+#define IEVENT_RXB (1 << 15)
+#define IEVENT_XFUN (1 << 16)
+#define IEVENT_CRL (1 << 17)
+#define IEVENT_LC (1 << 18)
+#define IEVENT_TXF (1 << 20)
+#define IEVENT_TXB (1 << 21)
+#define IEVENT_TXE (1 << 22)
+#define IEVENT_TXC (1 << 23)
+#define IEVENT_BABT (1 << 24)
+#define IEVENT_GTSC (1 << 25)
+#define IEVENT_MSRO (1 << 26)
+#define IEVENT_EBERR (1 << 28)
+#define IEVENT_BSY (1 << 29)
+#define IEVENT_RXC (1 << 30)
+#define IEVENT_BABR (1 << 31)
+
+#define IMASK_RXFEN (1 << 7)
+#define IMASK_GRSCEN (1 << 8)
+#define IMASK_RXBEN (1 << 15)
+#define IMASK_TXFEN (1 << 20)
+#define IMASK_TXBEN (1 << 21)
+#define IMASK_GTSCEN (1 << 25)
+
+#define MACCFG1_TX_EN (1 << 0)
+#define MACCFG1_RX_EN (1 << 2)
+
+#define MACCFG2_CRC_EN (1 << 1)
+#define MACCFG2_PADCRC (1 << 2)
+
+#define MIIMCOM_READ (1 << 0)
+#define MIIMCOM_SCAN (1 << 1)
+
+#define RCTRL_PRSDEP_MASK (0x3)
+#define RCTRL_PRSDEP_OFFSET (6)
+#define RCTRL_RSF (1 << 2)
+
+/* Index of each register */
+
+#define TSEC_ID (0x000 / 4)
+#define TSEC_ID2 (0x004 / 4)
+#define IEVENT (0x010 / 4)
+#define IMASK (0x014 / 4)
+#define EDIS (0x018 / 4)
+#define ECNTRL (0x020 / 4)
+#define PTV (0x028 / 4)
+#define DMACTRL (0x02C / 4)
+#define TBIPA (0x030 / 4)
+#define TCTRL (0x100 / 4)
+#define TSTAT (0x104 / 4)
+#define DFVLAN (0x108 / 4)
+#define TXIC (0x110 / 4)
+#define TQUEUE (0x114 / 4)
+#define TR03WT (0x140 / 4)
+#define TR47WT (0x144 / 4)
+#define TBDBPH (0x180 / 4)
+#define TBPTR0 (0x184 / 4)
+#define TBPTR1 (0x18C / 4)
+#define TBPTR2 (0x194 / 4)
+#define TBPTR3 (0x19C / 4)
+#define TBPTR4 (0x1A4 / 4)
+#define TBPTR5 (0x1AC / 4)
+#define TBPTR6 (0x1B4 / 4)
+#define TBPTR7 (0x1BC / 4)
+#define TBASEH (0x200 / 4)
+#define TBASE0 (0x204 / 4)
+#define TBASE1 (0x20C / 4)
+#define TBASE2 (0x214 / 4)
+#define TBASE3 (0x21C / 4)
+#define TBASE4 (0x224 / 4)
+#define TBASE5 (0x22C / 4)
+#define TBASE6 (0x234 / 4)
+#define TBASE7 (0x23C / 4)
+#define TMR_TXTS1_ID (0x280 / 4)
+#define TMR_TXTS2_ID (0x284 / 4)
+#define TMR_TXTS1_H (0x2C0 / 4)
+#define TMR_TXTS1_L (0x2C4 / 4)
+#define TMR_TXTS2_H (0x2C8 / 4)
+#define TMR_TXTS2_L (0x2CC / 4)
+#define RCTRL (0x300 / 4)
+#define RSTAT (0x304 / 4)
+#define RXIC (0x310 / 4)
+#define RQUEUE (0x314 / 4)
+#define RBIFX (0x330 / 4)
+#define RQFAR (0x334 / 4)
+#define RQFCR (0x338 / 4)
+#define RQFPR (0x33C / 4)
+#define MRBLR (0x340 / 4)
+#define RBDBPH (0x380 / 4)
+#define RBPTR0 (0x384 / 4)
+#define RBPTR1 (0x38C / 4)
+#define RBPTR2 (0x394 / 4)
+#define RBPTR3 (0x39C / 4)
+#define RBPTR4 (0x3A4 / 4)
+#define RBPTR5 (0x3AC / 4)
+#define RBPTR6 (0x3B4 / 4)
+#define RBPTR7 (0x3BC / 4)
+#define RBASEH (0x400 / 4)
+#define RBASE0 (0x404 / 4)
+#define RBASE1 (0x40C / 4)
+#define RBASE2 (0x414 / 4)
+#define RBASE3 (0x41C / 4)
+#define RBASE4 (0x424 / 4)
+#define RBASE5 (0x42C / 4)
+#define RBASE6 (0x434 / 4)
+#define RBASE7 (0x43C / 4)
+#define TMR_RXTS_H (0x4C0 / 4)
+#define TMR_RXTS_L (0x4C4 / 4)
+#define MACCFG1 (0x500 / 4)
+#define MACCFG2 (0x504 / 4)
+#define IPGIFG (0x508 / 4)
+#define HAFDUP (0x50C / 4)
+#define MAXFRM (0x510 / 4)
+#define MIIMCFG (0x520 / 4)
+#define MIIMCOM (0x524 / 4)
+#define MIIMADD (0x528 / 4)
+#define MIIMCON (0x52C / 4)
+#define MIIMSTAT (0x530 / 4)
+#define MIIMIND (0x534 / 4)
+#define IFSTAT (0x53C / 4)
+#define MACSTNADDR1 (0x540 / 4)
+#define MACSTNADDR2 (0x544 / 4)
+#define MAC01ADDR1 (0x548 / 4)
+#define MAC01ADDR2 (0x54C / 4)
+#define MAC02ADDR1 (0x550 / 4)
+#define MAC02ADDR2 (0x554 / 4)
+#define MAC03ADDR1 (0x558 / 4)
+#define MAC03ADDR2 (0x55C / 4)
+#define MAC04ADDR1 (0x560 / 4)
+#define MAC04ADDR2 (0x564 / 4)
+#define MAC05ADDR1 (0x568 / 4)
+#define MAC05ADDR2 (0x56C / 4)
+#define MAC06ADDR1 (0x570 / 4)
+#define MAC06ADDR2 (0x574 / 4)
+#define MAC07ADDR1 (0x578 / 4)
+#define MAC07ADDR2 (0x57C / 4)
+#define MAC08ADDR1 (0x580 / 4)
+#define MAC08ADDR2 (0x584 / 4)
+#define MAC09ADDR1 (0x588 / 4)
+#define MAC09ADDR2 (0x58C / 4)
+#define MAC10ADDR1 (0x590 / 4)
+#define MAC10ADDR2 (0x594 / 4)
+#define MAC11ADDR1 (0x598 / 4)
+#define MAC11ADDR2 (0x59C / 4)
+#define MAC12ADDR1 (0x5A0 / 4)
+#define MAC12ADDR2 (0x5A4 / 4)
+#define MAC13ADDR1 (0x5A8 / 4)
+#define MAC13ADDR2 (0x5AC / 4)
+#define MAC14ADDR1 (0x5B0 / 4)
+#define MAC14ADDR2 (0x5B4 / 4)
+#define MAC15ADDR1 (0x5B8 / 4)
+#define MAC15ADDR2 (0x5BC / 4)
+#define TR64 (0x680 / 4)
+#define TR127 (0x684 / 4)
+#define TR255 (0x688 / 4)
+#define TR511 (0x68C / 4)
+#define TR1K (0x690 / 4)
+#define TRMAX (0x694 / 4)
+#define TRMGV (0x698 / 4)
+#define RBYT (0x69C / 4)
+#define RPKT (0x6A0 / 4)
+#define RFCS (0x6A4 / 4)
+#define RMCA (0x6A8 / 4)
+#define RBCA (0x6AC / 4)
+#define RXCF (0x6B0 / 4)
+#define RXPF (0x6B4 / 4)
+#define RXUO (0x6B8 / 4)
+#define RALN (0x6BC / 4)
+#define RFLR (0x6C0 / 4)
+#define RCDE (0x6C4 / 4)
+#define RCSE (0x6C8 / 4)
+#define RUND (0x6CC / 4)
+#define ROVR (0x6D0 / 4)
+#define RFRG (0x6D4 / 4)
+#define RJBR (0x6D8 / 4)
+#define RDRP (0x6DC / 4)
+#define TBYT (0x6E0 / 4)
+#define TPKT (0x6E4 / 4)
+#define TMCA (0x6E8 / 4)
+#define TBCA (0x6EC / 4)
+#define TXPF (0x6F0 / 4)
+#define TDFR (0x6F4 / 4)
+#define TEDF (0x6F8 / 4)
+#define TSCL (0x6FC / 4)
+#define TMCL (0x700 / 4)
+#define TLCL (0x704 / 4)
+#define TXCL (0x708 / 4)
+#define TNCL (0x70C / 4)
+#define TDRP (0x714 / 4)
+#define TJBR (0x718 / 4)
+#define TFCS (0x71C / 4)
+#define TXCF (0x720 / 4)
+#define TOVR (0x724 / 4)
+#define TUND (0x728 / 4)
+#define TFRG (0x72C / 4)
+#define CAR1 (0x730 / 4)
+#define CAR2 (0x734 / 4)
+#define CAM1 (0x738 / 4)
+#define CAM2 (0x73C / 4)
+#define RREJ (0x740 / 4)
+#define IGADDR0 (0x800 / 4)
+#define IGADDR1 (0x804 / 4)
+#define IGADDR2 (0x808 / 4)
+#define IGADDR3 (0x80C / 4)
+#define IGADDR4 (0x810 / 4)
+#define IGADDR5 (0x814 / 4)
+#define IGADDR6 (0x818 / 4)
+#define IGADDR7 (0x81C / 4)
+#define GADDR0 (0x880 / 4)
+#define GADDR1 (0x884 / 4)
+#define GADDR2 (0x888 / 4)
+#define GADDR3 (0x88C / 4)
+#define GADDR4 (0x890 / 4)
+#define GADDR5 (0x894 / 4)
+#define GADDR6 (0x898 / 4)
+#define GADDR7 (0x89C / 4)
+#define ATTR (0xBF8 / 4)
+#define ATTRELI (0xBFC / 4)
+#define RQPRM0 (0xC00 / 4)
+#define RQPRM1 (0xC04 / 4)
+#define RQPRM2 (0xC08 / 4)
+#define RQPRM3 (0xC0C / 4)
+#define RQPRM4 (0xC10 / 4)
+#define RQPRM5 (0xC14 / 4)
+#define RQPRM6 (0xC18 / 4)
+#define RQPRM7 (0xC1C / 4)
+#define RFBPTR0 (0xC44 / 4)
+#define RFBPTR1 (0xC4C / 4)
+#define RFBPTR2 (0xC54 / 4)
+#define RFBPTR3 (0xC5C / 4)
+#define RFBPTR4 (0xC64 / 4)
+#define RFBPTR5 (0xC6C / 4)
+#define RFBPTR6 (0xC74 / 4)
+#define RFBPTR7 (0xC7C / 4)
+#define TMR_CTRL (0xE00 / 4)
+#define TMR_TEVENT (0xE04 / 4)
+#define TMR_TEMASK (0xE08 / 4)
+#define TMR_PEVENT (0xE0C / 4)
+#define TMR_PEMASK (0xE10 / 4)
+#define TMR_STAT (0xE14 / 4)
+#define TMR_CNT_H (0xE18 / 4)
+#define TMR_CNT_L (0xE1C / 4)
+#define TMR_ADD (0xE20 / 4)
+#define TMR_ACC (0xE24 / 4)
+#define TMR_PRSC (0xE28 / 4)
+#define TMROFF_H (0xE30 / 4)
+#define TMROFF_L (0xE34 / 4)
+#define TMR_ALARM1_H (0xE40 / 4)
+#define TMR_ALARM1_L (0xE44 / 4)
+#define TMR_ALARM2_H (0xE48 / 4)
+#define TMR_ALARM2_L (0xE4C / 4)
+#define TMR_FIPER1 (0xE80 / 4)
+#define TMR_FIPER2 (0xE84 / 4)
+#define TMR_FIPER3 (0xE88 / 4)
+#define TMR_ETTS1_H (0xEA0 / 4)
+#define TMR_ETTS1_L (0xEA4 / 4)
+#define TMR_ETTS2_H (0xEA8 / 4)
+#define TMR_ETTS2_L (0xEAC / 4)
+
+#endif /* ! _ETSEC_REGISTERS_H_ */
diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c
new file mode 100644
index 0000000000..77602722b3
--- /dev/null
+++ b/hw/net/fsl_etsec/rings.c
@@ -0,0 +1,650 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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 "net/checksum.h"
+
+#include "etsec.h"
+#include "registers.h"
+
+/* #define ETSEC_RING_DEBUG */
+/* #define HEX_DUMP */
+/* #define DEBUG_BD */
+
+#ifdef ETSEC_RING_DEBUG
+static const int debug_etsec = 1;
+#else
+static const int debug_etsec;
+#endif
+
+#define RING_DEBUG(fmt, ...) do { \
+ if (debug_etsec) { \
+ qemu_log(fmt , ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+#ifdef DEBUG_BD
+
+static void print_tx_bd_flags(uint16_t flags)
+{
+ qemu_log(" Ready: %d\n", !!(flags & BD_TX_READY));
+ qemu_log(" PAD/CRC: %d\n", !!(flags & BD_TX_PADCRC));
+ qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
+ qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
+ qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
+ qemu_log(" Tx CRC: %d\n", !!(flags & BD_TX_TC));
+ qemu_log(" User-defined preamble / defer: %d\n",
+ !!(flags & BD_TX_PREDEF));
+ qemu_log(" Huge frame enable / Late collision: %d\n",
+ !!(flags & BD_TX_HFELC));
+ qemu_log(" Control frame / Retransmission Limit: %d\n",
+ !!(flags & BD_TX_CFRL));
+ qemu_log(" Retry count: %d\n",
+ (flags >> BD_TX_RC_OFFSET) & BD_TX_RC_MASK);
+ qemu_log(" Underrun / TCP/IP off-load enable: %d\n",
+ !!(flags & BD_TX_TOEUN));
+ qemu_log(" Truncation: %d\n", !!(flags & BD_TX_TR));
+}
+
+static void print_rx_bd_flags(uint16_t flags)
+{
+ qemu_log(" Empty: %d\n", !!(flags & BD_RX_EMPTY));
+ qemu_log(" Receive software ownership: %d\n", !!(flags & BD_RX_RO1));
+ qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
+ qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
+ qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
+ qemu_log(" First in frame: %d\n", !!(flags & BD_RX_FIRST));
+ qemu_log(" Miss: %d\n", !!(flags & BD_RX_MISS));
+ qemu_log(" Broadcast: %d\n", !!(flags & BD_RX_BROADCAST));
+ qemu_log(" Multicast: %d\n", !!(flags & BD_RX_MULTICAST));
+ qemu_log(" Rx frame length violation: %d\n", !!(flags & BD_RX_LG));
+ qemu_log(" Rx non-octet aligned frame: %d\n", !!(flags & BD_RX_NO));
+ qemu_log(" Short frame: %d\n", !!(flags & BD_RX_SH));
+ qemu_log(" Rx CRC Error: %d\n", !!(flags & BD_RX_CR));
+ qemu_log(" Overrun: %d\n", !!(flags & BD_RX_OV));
+ qemu_log(" Truncation: %d\n", !!(flags & BD_RX_TR));
+}
+
+
+static void print_bd(eTSEC_rxtx_bd bd, int mode, uint32_t index)
+{
+ qemu_log("eTSEC %s Data Buffer Descriptor (%u)\n",
+ mode == eTSEC_TRANSMIT ? "Transmit" : "Receive",
+ index);
+ qemu_log(" Flags : 0x%04x\n", bd.flags);
+ if (mode == eTSEC_TRANSMIT) {
+ print_tx_bd_flags(bd.flags);
+ } else {
+ print_rx_bd_flags(bd.flags);
+ }
+ qemu_log(" Length : 0x%04x\n", bd.length);
+ qemu_log(" Pointer : 0x%08x\n", bd.bufptr);
+}
+
+#endif /* DEBUG_BD */
+
+static void read_buffer_descriptor(eTSEC *etsec,
+ hwaddr addr,
+ eTSEC_rxtx_bd *bd)
+{
+ assert(bd != NULL);
+
+ RING_DEBUG("READ Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
+ cpu_physical_memory_read(addr,
+ bd,
+ sizeof(eTSEC_rxtx_bd));
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
+ bd->flags = lduw_le_p(&bd->flags);
+ bd->length = lduw_le_p(&bd->length);
+ bd->bufptr = ldl_le_p(&bd->bufptr);
+ } else {
+ bd->flags = lduw_be_p(&bd->flags);
+ bd->length = lduw_be_p(&bd->length);
+ bd->bufptr = ldl_be_p(&bd->bufptr);
+ }
+}
+
+static void write_buffer_descriptor(eTSEC *etsec,
+ hwaddr addr,
+ eTSEC_rxtx_bd *bd)
+{
+ assert(bd != NULL);
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
+ stw_le_p(&bd->flags, bd->flags);
+ stw_le_p(&bd->length, bd->length);
+ stl_le_p(&bd->bufptr, bd->bufptr);
+ } else {
+ stw_be_p(&bd->flags, bd->flags);
+ stw_be_p(&bd->length, bd->length);
+ stl_be_p(&bd->bufptr, bd->bufptr);
+ }
+
+ RING_DEBUG("Write Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
+ cpu_physical_memory_write(addr,
+ bd,
+ sizeof(eTSEC_rxtx_bd));
+}
+
+static void ievent_set(eTSEC *etsec,
+ uint32_t flags)
+{
+ etsec->regs[IEVENT].value |= flags;
+
+ if ((flags & IEVENT_TXB && etsec->regs[IMASK].value & IMASK_TXBEN)
+ || (flags & IEVENT_TXF && etsec->regs[IMASK].value & IMASK_TXFEN)) {
+ qemu_irq_raise(etsec->tx_irq);
+ RING_DEBUG("%s Raise Tx IRQ\n", __func__);
+ }
+
+ if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN)
+ || (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) {
+ qemu_irq_pulse(etsec->rx_irq);
+ RING_DEBUG("%s Raise Rx IRQ\n", __func__);
+ }
+}
+
+static void tx_padding_and_crc(eTSEC *etsec, uint32_t min_frame_len)
+{
+ int add = min_frame_len - etsec->tx_buffer_len;
+
+ /* Padding */
+ if (add > 0) {
+ RING_DEBUG("pad:%u\n", add);
+ etsec->tx_buffer = g_realloc(etsec->tx_buffer,
+ etsec->tx_buffer_len + add);
+
+ memset(etsec->tx_buffer + etsec->tx_buffer_len, 0x0, add);
+ etsec->tx_buffer_len += add;
+ }
+
+ /* Never add CRC in QEMU */
+}
+
+static void process_tx_fcb(eTSEC *etsec)
+{
+ uint8_t flags = (uint8_t)(*etsec->tx_buffer);
+ /* L3 header offset from start of frame */
+ uint8_t l3_header_offset = (uint8_t)*(etsec->tx_buffer + 3);
+ /* L4 header offset from start of L3 header */
+ uint8_t l4_header_offset = (uint8_t)*(etsec->tx_buffer + 2);
+ /* L3 header */
+ uint8_t *l3_header = etsec->tx_buffer + 8 + l3_header_offset;
+ /* L4 header */
+ uint8_t *l4_header = l3_header + l4_header_offset;
+
+ /* if packet is IP4 and IP checksum is requested */
+ if (flags & FCB_TX_IP && flags & FCB_TX_CIP) {
+ /* do IP4 checksum (TODO This funtion does TCP/UDP checksum but not sure
+ * if it also does IP4 checksum. */
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ }
+ /* TODO Check the correct usage of the PHCS field of the FCB in case the NPH
+ * flag is on */
+
+ /* if packet is IP4 and TCP or UDP */
+ if (flags & FCB_TX_IP && flags & FCB_TX_TUP) {
+ /* if UDP */
+ if (flags & FCB_TX_UDP) {
+ /* if checksum is requested */
+ if (flags & FCB_TX_CTU) {
+ /* do UDP checksum */
+
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ } else {
+ /* set checksum field to 0 */
+ l4_header[6] = 0;
+ l4_header[7] = 0;
+ }
+ } else if (flags & FCB_TX_CTU) { /* if TCP and checksum is requested */
+ /* do TCP checksum */
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ }
+ }
+}
+
+static void process_tx_bd(eTSEC *etsec,
+ eTSEC_rxtx_bd *bd)
+{
+ uint8_t *tmp_buff = NULL;
+ hwaddr tbdbth = (hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32;
+
+ if (bd->length == 0) {
+ /* ERROR */
+ return;
+ }
+
+ if (etsec->tx_buffer_len == 0) {
+ /* It's the first BD */
+ etsec->first_bd = *bd;
+ }
+
+ /* TODO: if TxBD[TOE/UN] skip the Tx Frame Control Block*/
+
+ /* Load this Data Buffer */
+ etsec->tx_buffer = g_realloc(etsec->tx_buffer,
+ etsec->tx_buffer_len + bd->length);
+ tmp_buff = etsec->tx_buffer + etsec->tx_buffer_len;
+ cpu_physical_memory_read(bd->bufptr + tbdbth, tmp_buff, bd->length);
+
+ /* Update buffer length */
+ etsec->tx_buffer_len += bd->length;
+
+
+ if (etsec->tx_buffer_len != 0 && (bd->flags & BD_LAST)) {
+ if (etsec->regs[MACCFG1].value & MACCFG1_TX_EN) {
+ /* MAC Transmit enabled */
+
+ /* Process offload Tx FCB */
+ if (etsec->first_bd.flags & BD_TX_TOEUN) {
+ process_tx_fcb(etsec);
+ }
+
+ if (etsec->first_bd.flags & BD_TX_PADCRC
+ || etsec->regs[MACCFG2].value & MACCFG2_PADCRC) {
+
+ /* Padding and CRC (Padding implies CRC) */
+ tx_padding_and_crc(etsec, 64);
+
+ } else if (etsec->first_bd.flags & BD_TX_TC
+ || etsec->regs[MACCFG2].value & MACCFG2_CRC_EN) {
+
+ /* Only CRC */
+ /* Never add CRC in QEMU */
+ }
+
+#if defined(HEX_DUMP)
+ qemu_log("eTSEC Send packet size:%d\n", etsec->tx_buffer_len);
+ qemu_hexdump(etsec->tx_buffer, stderr, "", etsec->tx_buffer_len);
+#endif /* ETSEC_RING_DEBUG */
+
+ if (etsec->first_bd.flags & BD_TX_TOEUN) {
+ qemu_send_packet(qemu_get_queue(etsec->nic),
+ etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ } else {
+ qemu_send_packet(qemu_get_queue(etsec->nic),
+ etsec->tx_buffer,
+ etsec->tx_buffer_len);
+ }
+
+ }
+
+ etsec->tx_buffer_len = 0;
+
+ if (bd->flags & BD_INTERRUPT) {
+ ievent_set(etsec, IEVENT_TXF);
+ }
+ } else {
+ if (bd->flags & BD_INTERRUPT) {
+ ievent_set(etsec, IEVENT_TXB);
+ }
+ }
+
+ /* Update DB flags */
+
+ /* Clear Ready */
+ bd->flags &= ~BD_TX_READY;
+
+ /* Clear Defer */
+ bd->flags &= ~BD_TX_PREDEF;
+
+ /* Clear Late Collision */
+ bd->flags &= ~BD_TX_HFELC;
+
+ /* Clear Retransmission Limit */
+ bd->flags &= ~BD_TX_CFRL;
+
+ /* Clear Retry Count */
+ bd->flags &= ~(BD_TX_RC_MASK << BD_TX_RC_OFFSET);
+
+ /* Clear Underrun */
+ bd->flags &= ~BD_TX_TOEUN;
+
+ /* Clear Truncation */
+ bd->flags &= ~BD_TX_TR;
+}
+
+void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr)
+{
+ hwaddr ring_base = 0;
+ hwaddr bd_addr = 0;
+ eTSEC_rxtx_bd bd;
+ uint16_t bd_flags;
+
+ if (!(etsec->regs[MACCFG1].value & MACCFG1_TX_EN)) {
+ RING_DEBUG("%s: MAC Transmit not enabled\n", __func__);
+ return;
+ }
+
+ ring_base = (hwaddr)(etsec->regs[TBASEH].value & 0xF) << 32;
+ ring_base += etsec->regs[TBASE0 + ring_nbr].value & ~0x7;
+ bd_addr = etsec->regs[TBPTR0 + ring_nbr].value & ~0x7;
+
+ do {
+ read_buffer_descriptor(etsec, bd_addr, &bd);
+
+#ifdef DEBUG_BD
+ print_bd(bd,
+ eTSEC_TRANSMIT,
+ (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
+
+#endif /* DEBUG_BD */
+
+ /* Save flags before BD update */
+ bd_flags = bd.flags;
+
+ if (bd_flags & BD_TX_READY) {
+ process_tx_bd(etsec, &bd);
+
+ /* Write back BD after update */
+ write_buffer_descriptor(etsec, bd_addr, &bd);
+ }
+
+ /* Wrap or next BD */
+ if (bd_flags & BD_WRAP) {
+ bd_addr = ring_base;
+ } else {
+ bd_addr += sizeof(eTSEC_rxtx_bd);
+ }
+
+ } while (bd_addr != ring_base);
+
+ bd_addr = ring_base;
+
+ /* Save the Buffer Descriptor Pointers to current bd */
+ etsec->regs[TBPTR0 + ring_nbr].value = bd_addr;
+
+ /* Set transmit halt THLTx */
+ etsec->regs[TSTAT].value |= 1 << (31 - ring_nbr);
+}
+
+static void fill_rx_bd(eTSEC *etsec,
+ eTSEC_rxtx_bd *bd,
+ const uint8_t **buf,
+ size_t *size)
+{
+ uint16_t to_write;
+ hwaddr bufptr = bd->bufptr +
+ ((hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32);
+ uint8_t padd[etsec->rx_padding];
+ uint8_t rem;
+
+ RING_DEBUG("eTSEC fill Rx buffer @ 0x%016" HWADDR_PRIx
+ " size:%zu(padding + crc:%u) + fcb:%u\n",
+ bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size);
+
+ bd->length = 0;
+
+ /* This operation will only write FCB */
+ if (etsec->rx_fcb_size != 0) {
+
+ cpu_physical_memory_write(bufptr, etsec->rx_fcb, etsec->rx_fcb_size);
+
+ bufptr += etsec->rx_fcb_size;
+ bd->length += etsec->rx_fcb_size;
+ etsec->rx_fcb_size = 0;
+
+ }
+
+ /* We remove padding from the computation of to_write because it is not
+ * allocated in the buffer.
+ */
+ to_write = MIN(*size - etsec->rx_padding,
+ etsec->regs[MRBLR].value - etsec->rx_fcb_size);
+
+ /* This operation can only write packet data and no padding */
+ if (to_write > 0) {
+ cpu_physical_memory_write(bufptr, *buf, to_write);
+
+ *buf += to_write;
+ bufptr += to_write;
+ *size -= to_write;
+
+ bd->flags &= ~BD_RX_EMPTY;
+ bd->length += to_write;
+ }
+
+ if (*size == etsec->rx_padding) {
+ /* The remaining bytes are only for padding which is not actually
+ * allocated in the data buffer.
+ */
+
+ rem = MIN(etsec->regs[MRBLR].value - bd->length, etsec->rx_padding);
+
+ if (rem > 0) {
+ memset(padd, 0x0, sizeof(padd));
+ etsec->rx_padding -= rem;
+ *size -= rem;
+ bd->length += rem;
+ cpu_physical_memory_write(bufptr, padd, rem);
+ }
+ }
+}
+
+static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
+{
+ uint32_t fcb_size = 0;
+ uint8_t prsdep = (etsec->regs[RCTRL].value >> RCTRL_PRSDEP_OFFSET)
+ & RCTRL_PRSDEP_MASK;
+
+ if (prsdep != 0) {
+ /* Prepend FCB (FCB size + RCTRL[PAL]) */
+ fcb_size = 8 + ((etsec->regs[RCTRL].value >> 16) & 0x1F);
+
+ etsec->rx_fcb_size = fcb_size;
+
+ /* TODO: fill_FCB(etsec); */
+ memset(etsec->rx_fcb, 0x0, sizeof(etsec->rx_fcb));
+
+ } else {
+ etsec->rx_fcb_size = 0;
+ }
+
+ if (etsec->rx_buffer != NULL) {
+ g_free(etsec->rx_buffer);
+ }
+
+ /* Do not copy the frame for now */
+ etsec->rx_buffer = (uint8_t *)buf;
+ etsec->rx_buffer_len = size;
+
+ /* CRC padding (We don't have to compute the CRC) */
+ etsec->rx_padding = 4;
+
+ etsec->rx_first_in_frame = 1;
+ etsec->rx_remaining_data = etsec->rx_buffer_len;
+ RING_DEBUG("%s: rx_buffer_len:%u rx_padding+crc:%u\n", __func__,
+ etsec->rx_buffer_len, etsec->rx_padding);
+}
+
+void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
+{
+ int ring_nbr = 0; /* Always use ring0 (no filer) */
+
+ if (etsec->rx_buffer_len != 0) {
+ RING_DEBUG("%s: We can't receive now,"
+ " a buffer is already in the pipe\n", __func__);
+ return;
+ }
+
+ if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) {
+ RING_DEBUG("%s: The ring is halted\n", __func__);
+ return;
+ }
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_GRS) {
+ RING_DEBUG("%s: Graceful receive stop\n", __func__);
+ return;
+ }
+
+ if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) {
+ RING_DEBUG("%s: MAC Receive not enabled\n", __func__);
+ return;
+ }
+
+ if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) {
+ /* CRC is not in the packet yet, so short frame is below 60 bytes */
+ RING_DEBUG("%s: Drop short frame\n", __func__);
+ return;
+ }
+
+ rx_init_frame(etsec, buf, size);
+
+ etsec_walk_rx_ring(etsec, ring_nbr);
+}
+
+void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
+{
+ hwaddr ring_base = 0;
+ hwaddr bd_addr = 0;
+ hwaddr start_bd_addr = 0;
+ eTSEC_rxtx_bd bd;
+ uint16_t bd_flags;
+ size_t remaining_data;
+ const uint8_t *buf;
+ uint8_t *tmp_buf;
+ size_t size;
+
+ if (etsec->rx_buffer_len == 0) {
+ /* No frame to send */
+ RING_DEBUG("No frame to send\n");
+ return;
+ }
+
+ remaining_data = etsec->rx_remaining_data + etsec->rx_padding;
+ buf = etsec->rx_buffer
+ + (etsec->rx_buffer_len - etsec->rx_remaining_data);
+ size = etsec->rx_buffer_len + etsec->rx_padding;
+
+ ring_base = (hwaddr)(etsec->regs[RBASEH].value & 0xF) << 32;
+ ring_base += etsec->regs[RBASE0 + ring_nbr].value & ~0x7;
+ start_bd_addr = bd_addr = etsec->regs[RBPTR0 + ring_nbr].value & ~0x7;
+
+ do {
+ read_buffer_descriptor(etsec, bd_addr, &bd);
+
+#ifdef DEBUG_BD
+ print_bd(bd,
+ eTSEC_RECEIVE,
+ (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
+
+#endif /* DEBUG_BD */
+
+ /* Save flags before BD update */
+ bd_flags = bd.flags;
+
+ if (bd_flags & BD_RX_EMPTY) {
+ fill_rx_bd(etsec, &bd, &buf, &remaining_data);
+
+ if (etsec->rx_first_in_frame) {
+ bd.flags |= BD_RX_FIRST;
+ etsec->rx_first_in_frame = 0;
+ etsec->rx_first_bd = bd;
+ }
+
+ /* Last in frame */
+ if (remaining_data == 0) {
+
+ /* Clear flags */
+
+ bd.flags &= ~0x7ff;
+
+ bd.flags |= BD_LAST;
+
+ /* NOTE: non-octet aligned frame is impossible in qemu */
+
+ if (size >= etsec->regs[MAXFRM].value) {
+ /* frame length violation */
+ qemu_log("%s frame length violation: size:%zu MAXFRM:%d\n",
+ __func__, size, etsec->regs[MAXFRM].value);
+
+ bd.flags |= BD_RX_LG;
+ }
+
+ if (size < 64) {
+ /* Short frame */
+ bd.flags |= BD_RX_SH;
+ }
+
+ /* TODO: Broadcast and Multicast */
+
+ if (bd.flags | BD_INTERRUPT) {
+ /* Set RXFx */
+ etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr);
+
+ /* Set IEVENT */
+ ievent_set(etsec, IEVENT_RXF);
+ }
+
+ } else {
+ if (bd.flags | BD_INTERRUPT) {
+ /* Set IEVENT */
+ ievent_set(etsec, IEVENT_RXB);
+ }
+ }
+
+ /* Write back BD after update */
+ write_buffer_descriptor(etsec, bd_addr, &bd);
+ }
+
+ /* Wrap or next BD */
+ if (bd_flags & BD_WRAP) {
+ bd_addr = ring_base;
+ } else {
+ bd_addr += sizeof(eTSEC_rxtx_bd);
+ }
+ } while (remaining_data != 0
+ && (bd_flags & BD_RX_EMPTY)
+ && bd_addr != start_bd_addr);
+
+ /* Reset ring ptr */
+ etsec->regs[RBPTR0 + ring_nbr].value = bd_addr;
+
+ /* The frame is too large to fit in the Rx ring */
+ if (remaining_data > 0) {
+
+ /* Set RSTAT[QHLTx] */
+ etsec->regs[RSTAT].value |= 1 << (23 - ring_nbr);
+
+ /* Save remaining data to send the end of the frame when the ring will
+ * be restarted
+ */
+ etsec->rx_remaining_data = remaining_data;
+
+ /* Copy the frame */
+ tmp_buf = g_malloc(size);
+ memcpy(tmp_buf, etsec->rx_buffer, size);
+ etsec->rx_buffer = tmp_buf;
+
+ RING_DEBUG("no empty RxBD available any more\n");
+ } else {
+ etsec->rx_buffer_len = 0;
+ etsec->rx_buffer = NULL;
+ }
+
+ RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data);
+}
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 1bd6f50aaa..f6fbcb56bf 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -405,6 +405,8 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
dev->rx_bufs++;
+ qemu_flush_queued_packets(qemu_get_queue(dev->nic));
+
DPRINTF("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d"
" bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
(unsigned long long)buf);
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 3c0342e17a..fd23c4627e 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -397,12 +397,15 @@ static int peer_detach(VirtIONet *n, int index)
static void virtio_net_set_queues(VirtIONet *n)
{
int i;
+ int r;
for (i = 0; i < n->max_queues; i++) {
if (i < n->curr_queues) {
- assert(!peer_attach(n, i));
+ r = peer_attach(n, i);
+ assert(!r);
} else {
- assert(!peer_detach(n, i));
+ r = peer_detach(n, i);
+ assert(!r);
}
}
}
diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c
index ec6be4676c..e1e95aabcd 100644
--- a/hw/pci-host/pam.c
+++ b/hw/pci-host/pam.c
@@ -68,7 +68,7 @@ void init_pam(DeviceState *dev, MemoryRegion *ram_memory,
/* XXX: should distinguish read/write cases */
memory_region_init_alias(&mem->alias[0], OBJECT(dev), "pam-pci", pci_address_space,
start, size);
- memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", pci_address_space,
+ memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", ram_memory,
start, size);
for (i = 0; i < 4; ++i) {
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 8ecd11eca2..02cde6f96c 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -221,29 +221,23 @@ static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
DeviceState *dev,
uint8_t **exp_cap, Error **errp)
{
- PCIDevice *pci_dev = PCI_DEVICE(dev);
*exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
- PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
+ PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: %d\n", state);
if (sltsta & PCI_EXP_SLTSTA_EIS) {
/* the slot is electromechanically locked.
* This error is propagated up to qdev and then to HMP/QMP.
*/
error_setg_errno(errp, -EBUSY, "slot is electromechanically locked");
}
-
- /* TODO: multifunction hot-plug.
- * Right now, only a device of function = 0 is allowed to be
- * hot plugged/unplugged.
- */
- assert(PCI_FUNC(pci_dev->devfn) == 0);
}
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
uint8_t *exp_cap;
+ PCIDevice *pci_dev = PCI_DEVICE(dev);
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
@@ -256,6 +250,12 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
+ /* TODO: multifunction hot-plug.
+ * Right now, only a device of function = 0 is allowed to be
+ * hot plugged/unplugged.
+ */
+ assert(PCI_FUNC(pci_dev->devfn) == 0);
+
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b37ce9d633..8a08752613 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -238,6 +238,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
the first node as boot node and be happy */
for (i = smp_cpus - 1; i >= 0; i--) {
CPUState *cpu;
+ PowerPCCPU *pcpu;
char cpu_name[128];
uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
@@ -246,14 +247,16 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
continue;
}
env = cpu->env_ptr;
+ pcpu = POWERPC_CPU(cpu);
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
- cpu->cpu_index);
+ ppc_get_vcpu_dt_id(pcpu));
qemu_fdt_add_subnode(fdt, cpu_name);
qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
- qemu_fdt_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
+ ppc_get_vcpu_dt_id(pcpu));
qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
env->dcache_line_size);
qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 114be64480..0e82719b69 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -26,6 +26,7 @@
#include "hw/ppc/ppc_e500.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/cpus.h"
#include "hw/timer/m48t59.h"
#include "qemu/log.h"
#include "hw/loader.h"
@@ -1362,3 +1363,24 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
return 0;
}
+
+/* CPU device-tree ID helpers */
+int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
+{
+ return cpu->cpu_dt_id;
+}
+
+PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ if (cpu->cpu_dt_id == cpu_dt_id) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 93d02c1e50..bf46c380ec 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -49,6 +49,7 @@
#include "exec/address-spaces.h"
#include "hw/usb.h"
#include "qemu/config-file.h"
+#include "qemu/error-report.h"
#include <libfdt.h>
@@ -206,19 +207,20 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
CPU_FOREACH(cpu) {
DeviceClass *dc = DEVICE_GET_CLASS(cpu);
+ int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
uint32_t associativity[] = {cpu_to_be32(0x5),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(cpu->numa_node),
- cpu_to_be32(cpu->cpu_index)};
+ cpu_to_be32(index)};
- if ((cpu->cpu_index % smt) != 0) {
+ if ((index % smt) != 0) {
continue;
}
snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
- cpu->cpu_index);
+ index);
offset = fdt_path_offset(fdt, cpu_model);
if (offset < 0) {
@@ -367,7 +369,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
CPUPPCState *env = &cpu->env;
DeviceClass *dc = DEVICE_GET_CLASS(cs);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
- int index = cs->cpu_index;
+ int index = ppc_get_vcpu_dt_id(cpu);
uint32_t servers_prop[smp_threads];
uint32_t gservers_prop[smp_threads * 2];
char *nodename;
@@ -685,6 +687,7 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
if (shift > 0) {
/* Kernel handles htab, we don't need to allocate one */
spapr->htab_shift = shift;
+ kvmppc_kern_htab = true;
} else {
if (!spapr->htab) {
/* Allocate an htab if we don't yet have one */
@@ -740,8 +743,21 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
env->external_htab = (uint8_t *)spapr->htab;
+ if (kvm_enabled() && !env->external_htab) {
+ /*
+ * HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte*
+ * functions do the right thing.
+ */
+ env->external_htab = (void *)1;
+ }
env->htab_base = -1;
- env->htab_mask = HTAB_SIZE(spapr) - 1;
+ /*
+ * htab_mask is the mask used to normalize hash value to PTEG index.
+ * htab_shift is log2 of hash table size.
+ * We have 8 hpte per group, and each hpte is 16 bytes.
+ * ie have 128 bytes per hpte entry.
+ */
+ env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1;
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
(spapr->htab_shift - 18);
}
@@ -1305,20 +1321,15 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
- if (kernel_size < 0) {
+ if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
kernel_size = load_elf(kernel_filename,
translate_kernel_address, NULL,
NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0);
kernel_le = kernel_size > 0;
}
if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename,
- KERNEL_LOAD_ADDR,
- load_limit - KERNEL_LOAD_ADDR);
- }
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
+ fprintf(stderr, "qemu: error loading %s: %s\n",
+ kernel_filename, load_elf_strerror(kernel_size));
exit(1);
}
@@ -1366,6 +1377,24 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
assert(spapr->fdt_skel != NULL);
}
+static int spapr_kvm_type(const char *vm_type)
+{
+ if (!vm_type) {
+ return 0;
+ }
+
+ if (!strcmp(vm_type, "HV")) {
+ return 1;
+ }
+
+ if (!strcmp(vm_type, "PR")) {
+ return 2;
+ }
+
+ error_report("Unknown kvm-type specified '%s'", vm_type);
+ exit(1);
+}
+
static QEMUMachine spapr_machine = {
.name = "pseries",
.desc = "pSeries Logical Partition (PAPR compliant)",
@@ -1376,6 +1405,7 @@ static QEMUMachine spapr_machine = {
.max_cpus = MAX_CPUS,
.no_parallel = 1,
.default_boot_order = NULL,
+ .kvm_type = spapr_kvm_type,
};
static void spapr_machine_init(void)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 3ffcc65f03..d918780746 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -40,6 +40,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
return rb;
}
+static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
+{
+ /*
+ * hash value/pteg group index is normalized by htab_mask
+ */
+ if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
+ return false;
+ }
+ return true;
+}
+
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -50,8 +61,8 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong ptel = args[3];
target_ulong page_shift = 12;
target_ulong raddr;
- target_ulong i;
- hwaddr hpte;
+ target_ulong index;
+ uint64_t token;
/* only handle 4k and 16M pages for now */
if (pteh & HPTE64_V_LARGE) {
@@ -91,33 +102,37 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
pteh &= ~0x60ULL;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
+
+ index = 0;
if (likely((flags & H_EXACT) == 0)) {
pte_index &= ~7ULL;
- hpte = pte_index * HASH_PTE_SIZE_64;
- for (i = 0; ; ++i) {
- if (i == 8) {
+ token = ppc_hash64_start_access(cpu, pte_index);
+ do {
+ if (index == 8) {
+ ppc_hash64_stop_access(token);
return H_PTEG_FULL;
}
- if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
+ if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
break;
}
- hpte += HASH_PTE_SIZE_64;
- }
+ } while (index++);
+ ppc_hash64_stop_access(token);
} else {
- i = 0;
- hpte = pte_index * HASH_PTE_SIZE_64;
- if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
+ token = ppc_hash64_start_access(cpu, pte_index);
+ if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
+ ppc_hash64_stop_access(token);
return H_PTEG_FULL;
}
+ ppc_hash64_stop_access(token);
}
- ppc_hash64_store_hpte1(env, hpte, ptel);
- /* eieio(); FIXME: need some sort of barrier for smp? */
- ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY);
- args[0] = pte_index + i;
+ ppc_hash64_store_hpte(env, pte_index + index,
+ pteh | HPTE64_V_HPTE_DIRTY, ptel);
+
+ args[0] = pte_index + index;
return H_SUCCESS;
}
@@ -133,17 +148,17 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
target_ulong flags,
target_ulong *vp, target_ulong *rp)
{
- hwaddr hpte;
+ uint64_t token;
target_ulong v, r, rb;
- if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, ptex)) {
return REMOVE_PARM;
}
- hpte = ptex * HASH_PTE_SIZE_64;
-
- v = ppc_hash64_load_hpte0(env, hpte);
- r = ppc_hash64_load_hpte1(env, hpte);
+ token = ppc_hash64_start_access(ppc_env_get_cpu(env), ptex);
+ v = ppc_hash64_load_hpte0(env, token, 0);
+ r = ppc_hash64_load_hpte1(env, token, 0);
+ ppc_hash64_stop_access(token);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
@@ -152,7 +167,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
}
*vp = v;
*rp = r;
- ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, ptex, HPTE64_V_HPTE_DIRTY, 0);
rb = compute_tlbie_rb(v, r, ptex);
ppc_tlb_invalidate_one(env, rb);
return REMOVE_SUCCESS;
@@ -259,17 +274,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong flags = args[0];
target_ulong pte_index = args[1];
target_ulong avpn = args[2];
- hwaddr hpte;
+ uint64_t token;
target_ulong v, r, rb;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
- hpte = pte_index * HASH_PTE_SIZE_64;
-
- v = ppc_hash64_load_hpte0(env, hpte);
- r = ppc_hash64_load_hpte1(env, hpte);
+ token = ppc_hash64_start_access(cpu, pte_index);
+ v = ppc_hash64_load_hpte0(env, token, 0);
+ r = ppc_hash64_load_hpte1(env, token, 0);
+ ppc_hash64_stop_access(token);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
@@ -282,11 +297,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
r |= (flags << 48) & HPTE64_R_KEY_HI;
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
rb = compute_tlbie_rb(v, r, pte_index);
- ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, pte_index,
+ (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
ppc_tlb_invalidate_one(env, rb);
- ppc_hash64_store_hpte1(env, hpte, r);
/* Don't need a memory barrier, due to qemu's global lock */
- ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
return H_SUCCESS;
}
@@ -299,7 +314,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint8_t *hpte;
int i, ridx, n_entries = 1;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
@@ -467,13 +482,13 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong vpa = args[2];
target_ulong ret = H_PARAMETER;
CPUPPCState *tenv;
- CPUState *tcpu;
+ PowerPCCPU *tcpu;
- tcpu = qemu_get_cpu(procno);
+ tcpu = ppc_get_vcpu_by_dt_id(procno);
if (!tcpu) {
return H_PARAMETER;
}
- tenv = tcpu->env_ptr;
+ tenv = &tcpu->env;
switch (flags) {
case FLAGS_REGISTER_VPA:
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index ef45f4f0cc..d9fe946818 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -243,6 +243,42 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return ret;
}
+static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
+ target_ulong *tce)
+{
+ if (ioba >= tcet->window_size) {
+ hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x"
+ TARGET_FMT_lx "\n", ioba);
+ return H_PARAMETER;
+ }
+
+ *tce = tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT];
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong liobn = args[0];
+ target_ulong ioba = args[1];
+ target_ulong tce = 0;
+ target_ulong ret = H_PARAMETER;
+ sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+
+ ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
+
+ if (tcet) {
+ ret = get_tce_emu(tcet, ioba, &tce);
+ if (!ret) {
+ args[0] = tce;
+ }
+ }
+ trace_spapr_iommu_get(liobn, ioba, ret, tce);
+
+ return ret;
+}
+
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
uint32_t liobn, uint64_t window, uint32_t size)
{
@@ -295,6 +331,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
/* hcall-tce */
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+ spapr_register_hypercall(H_GET_TCE, h_get_tce);
}
static TypeInfo spapr_tce_table_info = {
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 4c7c3aec12..cea9469872 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -469,6 +469,8 @@ static const MemoryRegionOps spapr_msi_ops = {
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
{
+ uint64_t window_size = 4096;
+
/*
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
* we need to allocate some memory to catch those writes coming
@@ -476,10 +478,19 @@ void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
* As MSIMessage:addr is going to be the same and MSIMessage:data
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
* be used.
+ *
+ * For KVM we want to ensure that this memory is a full page so that
+ * our memory slot is of page size granularity.
*/
+#ifdef CONFIG_KVM
+ if (kvm_enabled()) {
+ window_size = getpagesize();
+ }
+#endif
+
spapr->msi_win_addr = addr;
memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
- "msi", getpagesize());
+ "msi", window_size);
memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
&spapr->msiwindow);
}
@@ -728,6 +739,8 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->props = spapr_phb_properties;
dc->reset = spapr_phb_reset;
dc->vmsd = &vmstate_spapr_pci;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->cannot_instantiate_with_device_add_yet = false;
}
static const TypeInfo spapr_phb_info = {
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 1cb276de05..73860d0486 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -131,7 +131,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
uint32_t nret, target_ulong rets)
{
target_ulong id;
- CPUState *cpu;
+ PowerPCCPU *cpu;
if (nargs != 1 || nret != 2) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
@@ -139,9 +139,9 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
}
id = rtas_ld(args, 0);
- cpu = qemu_get_cpu(id);
+ cpu = ppc_get_vcpu_by_dt_id(id);
if (cpu != NULL) {
- if (cpu->halted) {
+ if (CPU(cpu)->halted) {
rtas_st(rets, 1, 0);
} else {
rtas_st(rets, 1, 2);
@@ -161,7 +161,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
target_ulong id, start, r3;
- CPUState *cs;
+ PowerPCCPU *cpu;
if (nargs != 3 || nret != 1) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
@@ -172,9 +172,9 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
start = rtas_ld(args, 1);
r3 = rtas_ld(args, 2);
- cs = qemu_get_cpu(id);
- if (cs != NULL) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
+ cpu = ppc_get_vcpu_by_dt_id(id);
+ if (cpu != NULL) {
+ CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
if (!cs->halted) {
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 85a0e537b9..ce8ea91e8b 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -174,6 +174,19 @@ static int xilinx_load_device_tree(hwaddr addr,
if (!fdt) {
return 0;
}
+
+ r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
+ if (r < 0) {
+ error_report("couldn't set /chosen/linux,initrd-start");
+ }
+
+ r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
+ if (r < 0) {
+ error_report("couldn't set /chosen/linux,initrd-end");
+ }
+
r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
if (r < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
@@ -187,6 +200,8 @@ static void virtex_init(QEMUMachineInitArgs *args)
const char *cpu_model = args->cpu_model;
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
+ hwaddr initrd_base = 0;
+ int initrd_size = 0;
MemoryRegion *address_space_mem = get_system_memory();
DeviceState *dev;
PowerPCCPU *cpu;
@@ -259,10 +274,27 @@ static void virtex_init(QEMUMachineInitArgs *args)
boot_info.ima_size = kernel_size;
+ /* Load initrd. */
+ if (args->initrd_filename) {
+ initrd_base = high = ROUND_UP(high, 4);
+ initrd_size = load_image_targphys(args->initrd_filename,
+ high, ram_size - high);
+
+ if (initrd_size < 0) {
+ error_report("couldn't load ram disk '%s'",
+ args->initrd_filename);
+ exit(1);
+ }
+ high = ROUND_UP(high + initrd_size, 4);
+ }
+
/* Provide a device-tree. */
boot_info.fdt = high + (8192 * 2);
boot_info.fdt &= ~8191;
- xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
+
+ xilinx_load_device_tree(boot_info.fdt, ram_size,
+ initrd_base, initrd_size,
+ kernel_cmdline);
}
env->load_info = &boot_info;
}
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 75b04b45af..7074d2b3d5 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -116,6 +116,15 @@ void css_conditional_io_interrupt(SubchDev *sch)
}
}
+void css_adapter_interrupt(uint8_t isc)
+{
+ S390CPU *cpu = s390_cpu_addr2state(0);
+ uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
+
+ trace_css_adapter_interrupt(isc);
+ s390_io_interrupt(cpu, 0, 0, 0, io_int_word);
+}
+
static void sch_handle_clear_func(SubchDev *sch)
{
PMCW *p = &sch->curr_status.pmcw;
@@ -1259,6 +1268,7 @@ void css_reset_sch(SubchDev *sch)
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
sch->orb = NULL;
+ sch->thinint_active = false;
}
void css_reset(void)
diff --git a/hw/s390x/css.h b/hw/s390x/css.h
index b536ab5957..e9b440540d 100644
--- a/hw/s390x/css.h
+++ b/hw/s390x/css.h
@@ -77,6 +77,7 @@ struct SubchDev {
CCW1 last_cmd;
bool last_cmd_valid;
ORB *orb;
+ bool thinint_active;
/* transport-provided data: */
int (*ccw_cb) (SubchDev *, CCW1);
SenseId id;
@@ -97,4 +98,5 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid);
void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
int hotplugged, int add);
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
+void css_adapter_interrupt(uint8_t isc);
#endif
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index a73c0b924a..0777a93916 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -21,13 +21,13 @@
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
-typedef struct EventTypesBus {
+typedef struct SCLPEventsBus {
BusState qbus;
-} EventTypesBus;
+} SCLPEventsBus;
struct SCLPEventFacility {
- EventTypesBus sbus;
- DeviceState *qdev;
+ SysBusDevice parent_obj;
+ SCLPEventsBus sbus;
/* guest' receive mask */
unsigned int receive_mask;
};
@@ -291,7 +291,7 @@ static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
{
}
-static const TypeInfo s390_sclp_events_bus_info = {
+static const TypeInfo sclp_events_bus_info = {
.name = TYPE_SCLP_EVENTS_BUS,
.parent = TYPE_BUS,
.class_init = sclp_events_bus_class_init,
@@ -299,7 +299,7 @@ static const TypeInfo s390_sclp_events_bus_info = {
static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
{
- switch (code) {
+ switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMD_READ_EVENT_DATA:
read_event_data(ef, sccb);
break;
@@ -315,21 +315,26 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
}
}
-static int init_event_facility(S390SCLPDevice *sdev)
+static const VMStateDescription vmstate_event_facility = {
+ .name = "vmstate-event-facility",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(receive_mask, SCLPEventFacility),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int init_event_facility(SCLPEventFacility *event_facility)
{
- SCLPEventFacility *event_facility;
+ DeviceState *sdev = DEVICE(event_facility);
DeviceState *quiesce;
- event_facility = g_malloc0(sizeof(SCLPEventFacility));
- sdev->ef = event_facility;
- sdev->sclp_command_handler = command_handler;
- sdev->event_pending = event_pending;
-
- /* Spawn a new sclp-events facility */
+ /* Spawn a new bus for SCLP events */
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
- TYPE_SCLP_EVENTS_BUS, DEVICE(sdev), NULL);
+ TYPE_SCLP_EVENTS_BUS, sdev, NULL);
event_facility->sbus.qbus.allow_hotplug = 0;
- event_facility->qdev = (DeviceState *) sdev;
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
if (!quiesce) {
@@ -346,43 +351,57 @@ static int init_event_facility(S390SCLPDevice *sdev)
static void reset_event_facility(DeviceState *dev)
{
- S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev);
+ SCLPEventFacility *sdev = EVENT_FACILITY(dev);
- sdev->ef->receive_mask = 0;
+ sdev->receive_mask = 0;
}
static void init_event_facility_class(ObjectClass *klass, void *data)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
- S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(sbdc);
+ SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
dc->reset = reset_event_facility;
+ dc->vmsd = &vmstate_event_facility;
k->init = init_event_facility;
+ k->command_handler = command_handler;
+ k->event_pending = event_pending;
}
-static const TypeInfo s390_sclp_event_facility_info = {
- .name = "s390-sclp-event-facility",
- .parent = TYPE_DEVICE_S390_SCLP,
- .instance_size = sizeof(S390SCLPDevice),
+static const TypeInfo sclp_event_facility_info = {
+ .name = TYPE_SCLP_EVENT_FACILITY,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SCLPEventFacility),
.class_init = init_event_facility_class,
+ .class_size = sizeof(SCLPEventFacilityClass),
};
-static int event_qdev_init(DeviceState *qdev)
+static void event_realize(DeviceState *qdev, Error **errp)
{
- SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ SCLPEvent *event = SCLP_EVENT(qdev);
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
- return child->init(event);
+ if (child->init) {
+ int rc = child->init(event);
+ if (rc < 0) {
+ error_setg(errp, "SCLP event initialization failed.");
+ return;
+ }
+ }
}
-static int event_qdev_exit(DeviceState *qdev)
+static void event_unrealize(DeviceState *qdev, Error **errp)
{
- SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ SCLPEvent *event = SCLP_EVENT(qdev);
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
if (child->exit) {
- child->exit(event);
+ int rc = child->exit(event);
+ if (rc < 0) {
+ error_setg(errp, "SCLP event exit failed.");
+ return;
+ }
}
- return 0;
}
static void event_class_init(ObjectClass *klass, void *data)
@@ -391,11 +410,11 @@ static void event_class_init(ObjectClass *klass, void *data)
dc->bus_type = TYPE_SCLP_EVENTS_BUS;
dc->unplug = qdev_simple_unplug_cb;
- dc->init = event_qdev_init;
- dc->exit = event_qdev_exit;
+ dc->realize = event_realize;
+ dc->unrealize = event_unrealize;
}
-static const TypeInfo s390_sclp_event_type_info = {
+static const TypeInfo sclp_event_type_info = {
.name = TYPE_SCLP_EVENT,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SCLPEvent),
@@ -406,9 +425,9 @@ static const TypeInfo s390_sclp_event_type_info = {
static void register_types(void)
{
- type_register_static(&s390_sclp_events_bus_info);
- type_register_static(&s390_sclp_event_facility_info);
- type_register_static(&s390_sclp_event_type_info);
+ type_register_static(&sclp_events_bus_info);
+ type_register_static(&sclp_event_facility_info);
+ type_register_static(&sclp_event_type_info);
}
type_init(register_types)
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 1a6397b88e..32d38a08f6 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -95,24 +95,29 @@ static int s390_ipl_init(SysBusDevice *dev)
}
return 0;
} else {
- kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
+ uint64_t pentry = KERN_IMAGE_START;
+ kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
NULL, 1, ELF_MACHINE, 0);
- if (kernel_size == -1) {
+ if (kernel_size < 0) {
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
}
- if (kernel_size == -1) {
+ if (kernel_size < 0) {
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
return -1;
}
- /* we have to overwrite values in the kernel image, which are "rom" */
- strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
-
/*
- * we can not rely on the ELF entry point, since up to 3.2 this
- * value was 0x800 (the SALIPL loader) and it wont work. For
- * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
+ * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
+ * kernel parameters here as well. Note: For old kernels (up to 3.2)
+ * we can not rely on the ELF entry point - it was 0x800 (the SALIPL
+ * loader) and it won't work. For this case we force it to 0x10000, too.
*/
- ipl->start_addr = KERN_IMAGE_START;
+ if (pentry == KERN_IMAGE_START || pentry == 0x800) {
+ ipl->start_addr = KERN_IMAGE_START;
+ /* Overwrite parameters in the kernel image, which are "rom" */
+ strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
+ } else {
+ ipl->start_addr = pentry;
+ }
}
if (ipl->initrd) {
ram_addr_t initrd_offset;
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 733d988871..0d4f6ae2f3 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -13,13 +13,14 @@
#include "exec/address-spaces.h"
#include "s390-virtio.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/s390_flic.h"
#include "ioinst.h"
#include "css.h"
#include "virtio-ccw.h"
void io_subsystem_reset(void)
{
- DeviceState *css, *sclp;
+ DeviceState *css, *sclp, *flic;
css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
if (css) {
@@ -30,6 +31,10 @@ void io_subsystem_reset(void)
if (sclp) {
qdev_reset_all(sclp);
}
+ flic = DEVICE(object_resolve_path_type("", "s390-flic", NULL));
+ if (flic) {
+ qdev_reset_all(flic);
+ }
}
static int virtio_ccw_hcall_notify(const uint64_t *args)
@@ -99,6 +104,7 @@ static void ccw_init(QEMUMachineInitArgs *args)
s390_sclp_init();
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
args->initrd_filename, "s390-ccw.img");
+ s390_flic_init();
/* register hypercalls */
virtio_ccw_register_hcalls();
diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c
index ee626493c6..c7bdc2005d 100644
--- a/hw/s390x/s390-virtio-hcall.c
+++ b/hw/s390x/s390-virtio-hcall.c
@@ -26,11 +26,15 @@ void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
int s390_virtio_hypercall(CPUS390XState *env)
{
- s390_virtio_fn fn = s390_diag500_table[env->regs[1]];
-
- if (!fn) {
- return -EINVAL;
+ s390_virtio_fn fn;
+
+ if (env->regs[1] < MAX_DIAG_SUBCODES) {
+ fn = s390_diag500_table[env->regs[1]];
+ if (fn) {
+ env->regs[2] = fn(&env->regs[2]);
+ return 0;
+ }
}
- return fn(&env->regs[2]);
+ return -EINVAL;
}
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index 9eeda97920..0f03fd18b9 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -36,6 +36,7 @@
#include "hw/s390x/s390-virtio-bus.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/s390_flic.h"
#include "hw/s390x/s390-virtio.h"
//#define DEBUG_S390
@@ -251,6 +252,7 @@ static void s390_init(QEMUMachineInitArgs *args)
s390_sclp_init();
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
args->initrd_filename, ZIPL_FILENAME);
+ s390_flic_init();
/* register hypercalls */
s390_virtio_register_hcalls();
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 4e0c564c5c..d8ddf35e58 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -18,11 +18,12 @@
#include "sysemu/sysemu.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/event-facility.h"
-static inline S390SCLPDevice *get_event_facility(void)
+static inline SCLPEventFacility *get_event_facility(void)
{
ObjectProperty *op = object_property_find(qdev_get_machine(),
- "s390-sclp-event-facility",
+ TYPE_SCLP_EVENT_FACILITY,
NULL);
assert(op);
return op->opaque;
@@ -89,9 +90,10 @@ static void sclp_read_cpu_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
-static void sclp_execute(SCCB *sccb, uint64_t code)
+static void sclp_execute(SCCB *sccb, uint32_t code)
{
- S390SCLPDevice *sdev = get_event_facility();
+ SCLPEventFacility *ef = get_event_facility();
+ SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO:
@@ -102,12 +104,12 @@ static void sclp_execute(SCCB *sccb, uint64_t code)
sclp_read_cpu_info(sccb);
break;
default:
- sdev->sclp_command_handler(sdev->ef, sccb, code);
+ efc->command_handler(ef, sccb, code);
break;
}
}
-int sclp_service_call(uint32_t sccb, uint64_t code)
+int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
{
int r = 0;
SCCB work_sccb;
@@ -115,11 +117,16 @@ int sclp_service_call(uint32_t sccb, uint64_t code)
hwaddr sccb_len = sizeof(SCCB);
/* first some basic checks on program checks */
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ r = -PGM_PRIVILEGED;
+ goto out;
+ }
if (cpu_physical_memory_is_io(sccb)) {
r = -PGM_ADDRESSING;
goto out;
}
- if (sccb & ~0x7ffffff8ul) {
+ if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa
+ || (sccb & ~0x7ffffff8UL) != 0) {
r = -PGM_SPECIFICATION;
goto out;
}
@@ -151,11 +158,13 @@ out:
void sclp_service_interrupt(uint32_t sccb)
{
- S390SCLPDevice *sdev = get_event_facility();
+ SCLPEventFacility *ef = get_event_facility();
+ SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
+
uint32_t param = sccb & ~3;
/* Indicate whether an event is still pending */
- param |= sdev->event_pending(sdev->ef) ? 1 : 0;
+ param |= efc->event_pending(ef) ? 1 : 0;
if (!param) {
/* No need to send an interrupt, there's nothing to be notified about */
@@ -168,47 +177,9 @@ void sclp_service_interrupt(uint32_t sccb)
void s390_sclp_init(void)
{
- DeviceState *dev = qdev_create(NULL, "s390-sclp-event-facility");
+ DeviceState *dev = qdev_create(NULL, TYPE_SCLP_EVENT_FACILITY);
- object_property_add_child(qdev_get_machine(), "s390-sclp-event-facility",
+ object_property_add_child(qdev_get_machine(), TYPE_SCLP_EVENT_FACILITY,
OBJECT(dev), NULL);
qdev_init_nofail(dev);
}
-
-static int s390_sclp_dev_init(SysBusDevice *dev)
-{
- int r;
- S390SCLPDevice *sdev = (S390SCLPDevice *)dev;
- S390SCLPDeviceClass *sclp = SCLP_S390_DEVICE_GET_CLASS(dev);
-
- r = sclp->init(sdev);
- if (!r) {
- assert(sdev->event_pending);
- assert(sdev->sclp_command_handler);
- }
-
- return r;
-}
-
-static void s390_sclp_device_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass);
-
- dc->init = s390_sclp_dev_init;
-}
-
-static const TypeInfo s390_sclp_device_info = {
- .name = TYPE_DEVICE_S390_SCLP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(S390SCLPDevice),
- .class_init = s390_sclp_device_class_init,
- .class_size = sizeof(S390SCLPDeviceClass),
- .abstract = true,
-};
-
-static void s390_sclp_register_types(void)
-{
- type_register_static(&s390_sclp_device_info);
-}
-
-type_init(s390_sclp_register_types)
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index f6e0e3e4ae..a01801e342 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -1,7 +1,7 @@
/*
* virtio ccw target implementation
*
- * Copyright 2012 IBM Corp.
+ * Copyright 2012,2014 IBM Corp.
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
@@ -188,6 +188,13 @@ typedef struct VirtioFeatDesc {
uint8_t index;
} QEMU_PACKED VirtioFeatDesc;
+typedef struct VirtioThinintInfo {
+ hwaddr summary_indicator;
+ hwaddr device_indicator;
+ uint64_t ind_bit;
+ uint8_t isc;
+} QEMU_PACKED VirtioThinintInfo;
+
/* Specify where the virtqueues for the subchannel are in guest memory. */
static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
uint16_t index, uint16_t num)
@@ -237,6 +244,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
bool check_len;
int len;
hwaddr hw_len;
+ VirtioThinintInfo *thinint;
if (!dev) {
return -EINVAL;
@@ -428,6 +436,11 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EINVAL;
break;
}
+ if (sch->thinint_active) {
+ /* Trigger a command reject. */
+ ret = -ENOSYS;
+ break;
+ }
if (!ccw.cda) {
ret = -EFAULT;
} else {
@@ -480,6 +493,42 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = 0;
}
break;
+ case CCW_CMD_SET_IND_ADAPTER:
+ if (check_len) {
+ if (ccw.count != sizeof(*thinint)) {
+ ret = -EINVAL;
+ break;
+ }
+ } else if (ccw.count < sizeof(*thinint)) {
+ /* Can't execute command. */
+ ret = -EINVAL;
+ break;
+ }
+ len = sizeof(*thinint);
+ hw_len = len;
+ if (!ccw.cda) {
+ ret = -EFAULT;
+ } else if (dev->indicators && !sch->thinint_active) {
+ /* Trigger a command reject. */
+ ret = -ENOSYS;
+ } else {
+ thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
+ if (!thinint) {
+ ret = -EFAULT;
+ } else {
+ len = hw_len;
+ dev->summary_indicator = thinint->summary_indicator;
+ dev->indicators = thinint->device_indicator;
+ dev->thinint_isc = thinint->isc;
+ dev->ind_bit = thinint->ind_bit;
+ cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
+ sch->thinint_active = ((dev->indicators != 0) &&
+ (dev->summary_indicator != 0));
+ sch->curr_status.scsw.count = ccw.count - len;
+ ret = 0;
+ }
+ }
+ break;
default:
ret = -ENOSYS;
break;
@@ -511,6 +560,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
sch->orb = NULL;
+ sch->thinint_active = false;
/*
* Use a device number if provided. Otherwise, fall back to subchannel
* number.
@@ -858,6 +908,28 @@ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
return container_of(d, VirtioCcwDevice, parent_obj);
}
+static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
+ uint8_t to_be_set)
+{
+ uint8_t ind_old, ind_new;
+ hwaddr len = 1;
+ uint8_t *ind_addr;
+
+ ind_addr = cpu_physical_memory_map(ind_loc, &len, 1);
+ if (!ind_addr) {
+ error_report("%s(%x.%x.%04x): unable to access indicator",
+ __func__, sch->cssid, sch->ssid, sch->schid);
+ return -1;
+ }
+ do {
+ ind_old = *ind_addr;
+ ind_new = ind_old | to_be_set;
+ } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
+ cpu_physical_memory_unmap(ind_addr, len, 1, len);
+
+ return ind_old;
+}
+
static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
{
VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d);
@@ -872,9 +944,26 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
if (!dev->indicators) {
return;
}
- indicators = ldq_phys(&address_space_memory, dev->indicators);
- indicators |= 1ULL << vector;
- stq_phys(&address_space_memory, dev->indicators, indicators);
+ if (sch->thinint_active) {
+ /*
+ * In the adapter interrupt case, indicators points to a
+ * memory area that may be (way) larger than 64 bit and
+ * ind_bit indicates the start of the indicators in a big
+ * endian notation.
+ */
+ virtio_set_ind_atomic(sch, dev->indicators +
+ (dev->ind_bit + vector) / 8,
+ 0x80 >> ((dev->ind_bit + vector) % 8));
+ if (!virtio_set_ind_atomic(sch, dev->summary_indicator,
+ 0x01)) {
+ css_adapter_interrupt(dev->thinint_isc);
+ }
+ } else {
+ indicators = ldq_phys(&address_space_memory, dev->indicators);
+ indicators |= 1ULL << vector;
+ stq_phys(&address_space_memory, dev->indicators, indicators);
+ css_conditional_io_interrupt(sch);
+ }
} else {
if (!dev->indicators2) {
return;
@@ -883,10 +972,8 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
indicators = ldq_phys(&address_space_memory, dev->indicators2);
indicators |= 1ULL << vector;
stq_phys(&address_space_memory, dev->indicators2, indicators);
+ css_conditional_io_interrupt(sch);
}
-
- css_conditional_io_interrupt(sch);
-
}
static unsigned virtio_ccw_get_features(DeviceState *d)
@@ -907,6 +994,7 @@ static void virtio_ccw_reset(DeviceState *d)
css_reset_sch(dev->sch);
dev->indicators = 0;
dev->indicators2 = 0;
+ dev->summary_indicator = 0;
}
static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 00932c746d..4393e44814 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -38,6 +38,7 @@
#define CCW_CMD_SET_IND 0x43
#define CCW_CMD_SET_CONF_IND 0x53
#define CCW_CMD_READ_VQ_CONF 0x32
+#define CCW_CMD_SET_IND_ADAPTER 0x73
#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device"
#define VIRTIO_CCW_DEVICE(obj) \
@@ -83,9 +84,12 @@ struct VirtioCcwDevice {
bool ioeventfd_started;
bool ioeventfd_disabled;
uint32_t flags;
+ uint8_t thinint_isc;
/* Guest provided values: */
hwaddr indicators;
hwaddr indicators2;
+ hwaddr summary_indicator;
+ uint64_t ind_bit;
};
/* virtual css bus type */
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 50b89ad4aa..50a0acf1fe 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -909,7 +909,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
case VERIFY_16:
if ((buf[1] & 2) == 0) {
cmd->xfer = 0;
- } else if ((buf[1] & 4) == 1) {
+ } else if ((buf[1] & 4) != 0) {
cmd->xfer = 1;
}
cmd->xfer *= dev->blocksize;
@@ -1367,6 +1367,11 @@ const struct SCSISense sense_code_WRITE_PROTECTED = {
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
};
+/* Data Protection, Space Allocation Failed Write Protect */
+const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
+ .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
+};
+
/*
* scsi_build_sense
*
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index b4fadd2f24..48a28ae199 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -75,6 +75,8 @@ struct SCSIDiskState
bool media_event;
bool eject_request;
uint64_t wwn;
+ uint64_t port_wwn;
+ uint16_t port_index;
uint64_t max_unmap_size;
QEMUBH *bh;
char *version;
@@ -428,6 +430,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
case EINVAL:
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
break;
+ case ENOSPC:
+ scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
+ break;
default:
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
@@ -617,6 +622,24 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
stq_be_p(&outbuf[buflen], s->wwn);
buflen += 8;
}
+
+ if (s->port_wwn) {
+ outbuf[buflen++] = 0x61; // SAS / Binary
+ outbuf[buflen++] = 0x93; // PIV / Target port / NAA
+ outbuf[buflen++] = 0; // reserved
+ outbuf[buflen++] = 8;
+ stq_be_p(&outbuf[buflen], s->port_wwn);
+ buflen += 8;
+ }
+
+ if (s->port_index) {
+ outbuf[buflen++] = 0x61; // SAS / Binary
+ outbuf[buflen++] = 0x94; // PIV / Target port / relative target port
+ outbuf[buflen++] = 0; // reserved
+ outbuf[buflen++] = 4;
+ stw_be_p(&outbuf[buflen + 2], s->port_index);
+ buflen += 4;
+ }
break;
}
case 0xb0: /* block limits */
@@ -2536,6 +2559,8 @@ static Property scsi_hd_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
@@ -2584,6 +2609,8 @@ static const TypeInfo scsi_hd_info = {
static Property scsi_cd_properties[] = {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2647,6 +2674,8 @@ static Property scsi_disk_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index f08b64e177..8d92e0da15 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -37,8 +37,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#include <scsi/sg.h>
#include "block/scsi.h"
-#define SCSI_SENSE_BUF_SIZE 96
-
#define SG_ERR_DRIVER_TIMEOUT 0x06
#define SG_ERR_DRIVER_SENSE 0x08
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index c0c46d7f7c..b3835c821d 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -60,9 +60,10 @@
#define VSCSI_MAX_SECTORS 4096
#define VSCSI_REQ_LIMIT 24
-#define SCSI_SENSE_BUF_SIZE 96
#define SRP_RSP_SENSE_DATA_LEN 18
+#define SRP_REPORT_LUNS_WLUN 0xc10100000000000ULL
+
typedef union vscsi_crq {
struct viosrp_crq s;
uint8_t raw[16];
@@ -720,12 +721,70 @@ static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
}
}
+static void vscsi_report_luns(VSCSIState *s, vscsi_req *req)
+{
+ BusChild *kid;
+ int i, len, n, rc;
+ uint8_t *resp_data;
+ bool found_lun0;
+
+ n = 0;
+ found_lun0 = false;
+ QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+ SCSIDevice *dev = SCSI_DEVICE(kid->child);
+
+ n += 8;
+ if (dev->channel == 0 && dev->id == 0 && dev->lun == 0) {
+ found_lun0 = true;
+ }
+ }
+ if (!found_lun0) {
+ n += 8;
+ }
+ len = n+8;
+
+ resp_data = g_malloc0(len);
+ memset(resp_data, 0, len);
+ stl_be_p(resp_data, n);
+ i = found_lun0 ? 8 : 16;
+ QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
+
+ if (dev->id == 0 && dev->channel == 0) {
+ resp_data[i] = 0; /* Use simple LUN for 0 (SAM5 4.7.7.1) */
+ } else {
+ resp_data[i] = (2 << 6); /* Otherwise LUN addressing (4.7.7.4) */
+ }
+ resp_data[i] |= dev->id;
+ resp_data[i+1] = (dev->channel << 5);
+ resp_data[i+1] |= dev->lun;
+ i += 8;
+ }
+
+ vscsi_preprocess_desc(req);
+ rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
+ g_free(resp_data);
+ if (rc < 0) {
+ vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+ vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+ } else {
+ vscsi_send_rsp(s, req, 0, len - rc, 0);
+ }
+}
+
static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
{
union srp_iu *srp = &req->iu.srp;
SCSIDevice *sdev;
int n, lun;
+ if ((srp->cmd.lun == 0 || be64_to_cpu(srp->cmd.lun) == SRP_REPORT_LUNS_WLUN)
+ && srp->cmd.cdb[0] == REPORT_LUNS) {
+ vscsi_report_luns(s, req);
+ return 0;
+ }
+
sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
if (!sdev) {
DPRINTF("VSCSI: Command for lun %08" PRIx64 " with no drive\n",
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 2957d90177..75adb68abc 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "hw/sysbus.h"
+#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "hw/sparc/sun4m.h"
#include "hw/timer/m48t59.h"
@@ -561,6 +562,31 @@ static void tcx_init(hwaddr addr, int vram_size, int width,
}
}
+static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
+ int height, int depth)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ dev = qdev_create(NULL, "cgthree");
+ qdev_prop_set_uint32(dev, "vram-size", vram_size);
+ qdev_prop_set_uint16(dev, "width", width);
+ qdev_prop_set_uint16(dev, "height", height);
+ qdev_prop_set_uint16(dev, "depth", depth);
+ qdev_prop_set_uint64(dev, "prom-addr", addr);
+ qdev_init_nofail(dev);
+ s = SYS_BUS_DEVICE(dev);
+
+ /* FCode ROM */
+ sysbus_mmio_map(s, 0, addr);
+ /* DAC */
+ sysbus_mmio_map(s, 1, addr + 0x400000ULL);
+ /* 8-bit plane */
+ sysbus_mmio_map(s, 2, addr + 0x800000ULL);
+
+ sysbus_connect_irq(s, 0, irq);
+}
+
/* NCR89C100/MACIO Internal ID register */
#define TYPE_MACIO_ID_REGISTER "macio_idreg"
@@ -914,13 +940,43 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
slavio_irq[16], iommu, &ledma_irq, 1);
if (graphic_depth != 8 && graphic_depth != 24) {
- fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+ error_report("Unsupported depth: %d", graphic_depth);
exit (1);
}
num_vsimms = 0;
if (num_vsimms == 0) {
- tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
- graphic_depth);
+ if (vga_interface_type == VGA_CG3) {
+ if (graphic_depth != 8) {
+ error_report("Unsupported depth: %d", graphic_depth);
+ exit(1);
+ }
+
+ if (!(graphic_width == 1024 && graphic_height == 768) &&
+ !(graphic_width == 1152 && graphic_height == 900)) {
+ error_report("Unsupported resolution: %d x %d", graphic_width,
+ graphic_height);
+ exit(1);
+ }
+
+ /* sbus irq 5 */
+ cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000,
+ graphic_width, graphic_height, graphic_depth);
+ } else {
+ /* If no display specified, default to TCX */
+ if (graphic_depth != 8 && graphic_depth != 24) {
+ error_report("Unsupported depth: %d", graphic_depth);
+ exit(1);
+ }
+
+ if (!(graphic_width == 1024 && graphic_height == 768)) {
+ error_report("Unsupported resolution: %d x %d",
+ graphic_width, graphic_height);
+ exit(1);
+ }
+
+ tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+ graphic_depth);
+ }
}
for (i = num_vsimms; i < MAX_VSIMMS; i++) {
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 6a287464bf..8977243725 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -43,7 +43,7 @@
/* config register */
#define R_CONFIG (0x00 / 4)
-#define IFMODE (1 << 31)
+#define IFMODE (1U << 31)
#define ENDIAN (1 << 26)
#define MODEFAIL_GEN_EN (1 << 17)
#define MAN_START_COM (1 << 16)
@@ -87,7 +87,7 @@
#define R_LQSPI_CFG (0xa0 / 4)
#define R_LQSPI_CFG_RESET 0x03A002EB
-#define LQSPI_CFG_LQ_MODE (1 << 31)
+#define LQSPI_CFG_LQ_MODE (1U << 31)
#define LQSPI_CFG_TWO_MEM (1 << 30)
#define LQSPI_CFG_SEP_BUS (1 << 30)
#define LQSPI_CFG_U_PAGE (1 << 28)
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index f75b914951..e4dcceaf23 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -51,7 +51,7 @@ typedef struct CPUTimerState {
ptimer_state *timer;
uint32_t count, counthigh, reached;
/* processor only */
- uint32_t running;
+ uint32_t run;
uint64_t limit;
} CPUTimerState;
@@ -177,7 +177,7 @@ static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
// only available in processor counter/timer
// read start/stop status
if (timer_index > 0) {
- ret = t->running;
+ ret = t->run;
} else {
ret = 0;
}
@@ -260,16 +260,15 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
case TIMER_STATUS:
if (slavio_timer_is_user(tc)) {
// start/stop user counter
- if ((val & 1) && !t->running) {
+ if (val & 1) {
trace_slavio_timer_mem_writel_status_start(timer_index);
ptimer_run(t->timer, 0);
- t->running = 1;
- } else if (!(val & 1) && t->running) {
+ } else {
trace_slavio_timer_mem_writel_status_stop(timer_index);
ptimer_stop(t->timer);
- t->running = 0;
}
}
+ t->run = val & 1;
break;
case TIMER_MODE:
if (timer_index == 0) {
@@ -284,8 +283,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
if (val & processor) { // counter -> user timer
qemu_irq_lower(curr_timer->irq);
// counters are always running
- ptimer_stop(curr_timer->timer);
- curr_timer->running = 0;
+ if (!curr_timer->run) {
+ ptimer_stop(curr_timer->timer);
+ }
// user timer limit is always the same
curr_timer->limit = TIMER_MAX_COUNT64;
ptimer_set_limit(curr_timer->timer,
@@ -296,13 +296,8 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
s->cputimer_mode |= processor;
trace_slavio_timer_mem_writel_mode_user(timer_index);
} else { // user timer -> counter
- // stop the user timer if it is running
- if (curr_timer->running) {
- ptimer_stop(curr_timer->timer);
- }
// start the counter
ptimer_run(curr_timer->timer, 0);
- curr_timer->running = 1;
// clear this processors user timer bit in config
// register
s->cputimer_mode &= ~processor;
@@ -340,7 +335,7 @@ static const VMStateDescription vmstate_timer = {
VMSTATE_UINT32(count, CPUTimerState),
VMSTATE_UINT32(counthigh, CPUTimerState),
VMSTATE_UINT32(reached, CPUTimerState),
- VMSTATE_UINT32(running, CPUTimerState),
+ VMSTATE_UINT32(run , CPUTimerState),
VMSTATE_PTIMER(timer, CPUTimerState),
VMSTATE_END_OF_LIST()
}
@@ -373,7 +368,7 @@ static void slavio_timer_reset(DeviceState *d)
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
- curr_timer->running = 1;
+ curr_timer->run = 1;
}
}
s->cputimer_mode = 0;
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index e05cbc131e..42913b6a5a 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -98,7 +98,7 @@ static void puv3_load_kernel(const char *kernel_filename)
}
/* cheat curses that we have a graphic console, only under ocd console */
- graphic_console_init(NULL, &no_ops, NULL);
+ graphic_console_init(NULL, 0, &no_ops, NULL);
}
static void puv3_init(QEMUMachineInitArgs *args)
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index aa913df853..7213c8909c 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -546,10 +546,10 @@ static int emulated_initfn(CCIDCardState *base)
printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
return -1;
}
- qemu_thread_create(&card->event_thread_id, event_thread, card,
- QEMU_THREAD_JOINABLE);
- qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card,
- QEMU_THREAD_JOINABLE);
+ qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
+ card, QEMU_THREAD_JOINABLE);
+ qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
+ card, QEMU_THREAD_JOINABLE);
return 0;
}
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index 01cd8c7a2b..66a3d46938 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -59,6 +59,7 @@ typedef uint64_t target_ulong;
#define EXCP_HLT 0x10001 /* hlt instruction reached */
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
+#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */
#define TB_JMP_CACHE_BITS 12
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 9101fc3a55..c084db2d9d 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -836,13 +836,13 @@ void memory_region_set_alias_offset(MemoryRegion *mr,
hwaddr offset);
/**
- * memory_region_present: translate an address/size relative to a
- * MemoryRegion into a #MemoryRegionSection.
+ * memory_region_present: checks if an address relative to a @parent
+ * translates into #MemoryRegion within @parent
*
* Answer whether a #MemoryRegion within @parent covers the address
* @addr.
*
- * @parent: a MemoryRegion within which @addr is a relative address
+ * @parent: a #MemoryRegion within which @addr is a relative address
* @addr: the area within @parent to be searched
*/
bool memory_region_present(MemoryRegion *parent, hwaddr addr);
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 2151460f9e..c2096e6ba2 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -4,10 +4,9 @@
#define HW_BOARDS_H
#include "sysemu/blockdev.h"
+#include "sysemu/qemumachine.h"
#include "hw/qdev.h"
-typedef struct QEMUMachine QEMUMachine;
-
typedef struct QEMUMachineInitArgs {
const QEMUMachine *machine;
ram_addr_t ram_size;
@@ -24,6 +23,8 @@ typedef void QEMUMachineResetFunc(void);
typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp);
+typedef int QEMUMachineGetKvmtypeFunc(const char *arg);
+
struct QEMUMachine {
const char *name;
const char *alias;
@@ -31,6 +32,7 @@ struct QEMUMachine {
QEMUMachineInitFunc *init;
QEMUMachineResetFunc *reset;
QEMUMachineHotAddCPUFunc *hot_add_cpu;
+ QEMUMachineGetKvmtypeFunc *kvm_type;
BlockInterfaceType block_default_type;
int max_cpus;
unsigned int no_serial:1,
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index acc701e3a4..c6b5129bab 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -201,6 +201,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
uint64_t addr, low = (uint64_t)-1, high = 0;
uint8_t *data = NULL;
char label[128];
+ int ret = ELF_LOAD_FAILED;
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
goto fail;
@@ -211,22 +212,30 @@ static int glue(load_elf, SZ)(const char *name, int fd,
switch (elf_machine) {
case EM_PPC64:
if (EM_PPC64 != ehdr.e_machine)
- if (EM_PPC != ehdr.e_machine)
+ if (EM_PPC != ehdr.e_machine) {
+ ret = ELF_LOAD_WRONG_ARCH;
goto fail;
+ }
break;
case EM_X86_64:
if (EM_X86_64 != ehdr.e_machine)
- if (EM_386 != ehdr.e_machine)
+ if (EM_386 != ehdr.e_machine) {
+ ret = ELF_LOAD_WRONG_ARCH;
goto fail;
+ }
break;
case EM_MICROBLAZE:
if (EM_MICROBLAZE != ehdr.e_machine)
- if (EM_MICROBLAZE_OLD != ehdr.e_machine)
+ if (EM_MICROBLAZE_OLD != ehdr.e_machine) {
+ ret = ELF_LOAD_WRONG_ARCH;
goto fail;
+ }
break;
default:
- if (elf_machine != ehdr.e_machine)
+ if (elf_machine != ehdr.e_machine) {
+ ret = ELF_LOAD_WRONG_ARCH;
goto fail;
+ }
}
if (pentry)
@@ -305,5 +314,5 @@ static int glue(load_elf, SZ)(const char *name, int fd,
fail:
g_free(data);
g_free(phdr);
- return -1;
+ return ret;
}
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 91b01224a3..aaf08c377e 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -15,6 +15,12 @@ int get_image_size(const char *filename);
int load_image(const char *filename, uint8_t *addr); /* deprecated */
int load_image_targphys(const char *filename, hwaddr,
uint64_t max_sz);
+
+#define ELF_LOAD_FAILED -1
+#define ELF_LOAD_NOT_ELF -2
+#define ELF_LOAD_WRONG_ARCH -3
+#define ELF_LOAD_WRONG_ENDIAN -4
+const char *load_elf_strerror(int error);
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
uint64_t *highaddr, int big_endian, int elf_machine,
diff --git a/include/hw/nvram/openbios_firmware_abi.h b/include/hw/nvram/openbios_firmware_abi.h
index 5e6e5d4d34..c66ee22685 100644
--- a/include/hw/nvram/openbios_firmware_abi.h
+++ b/include/hw/nvram/openbios_firmware_abi.h
@@ -62,6 +62,8 @@ Sun_init_header(struct Sun_nvram *header, const uint8_t *macaddr, int machine_id
header->type = 1;
header->machine_id = machine_id & 0xff;
memcpy(&header->macaddr, macaddr, 6);
+ memcpy(&header->hostid , &macaddr[3], 3);
+
/* Calculate checksum */
tmp = 0;
tmpptr = (uint8_t *)header;
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 276b336c09..1ed0691716 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -176,6 +176,8 @@ struct BusClass {
void (*reset)(BusState *bus);
/* maximum devices allowed on the bus, 0: no limit. */
int max_dev;
+ /* number of automatically allocated bus ids (e.g. ide.0) */
+ int automatic_ids;
};
typedef struct BusChild {
diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h
index 870edd46f6..6a062b668a 100644
--- a/include/hw/s390x/event-facility.h
+++ b/include/hw/s390x/event-facility.h
@@ -176,4 +176,23 @@ typedef struct SCLPEventClass {
bool (*can_handle_event)(uint8_t type);
} SCLPEventClass;
+#define TYPE_SCLP_EVENT_FACILITY "s390-sclp-event-facility"
+#define EVENT_FACILITY(obj) \
+ OBJECT_CHECK(SCLPEventFacility, (obj), TYPE_SCLP_EVENT_FACILITY)
+#define EVENT_FACILITY_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SCLPEventFacilityClass, (klass), \
+ TYPE_SCLP_EVENT_FACILITY)
+#define EVENT_FACILITY_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \
+ TYPE_SCLP_EVENT_FACILITY)
+
+typedef struct SCLPEventFacility SCLPEventFacility;
+
+typedef struct SCLPEventFacilityClass {
+ DeviceClass parent_class;
+ int (*init)(SCLPEventFacility *ef);
+ void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code);
+ bool (*event_pending)(SCLPEventFacility *ef);
+} SCLPEventFacilityClass;
+
#endif
diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h
new file mode 100644
index 0000000000..497b219e30
--- /dev/null
+++ b/include/hw/s390x/s390_flic.h
@@ -0,0 +1,33 @@
+/*
+ * QEMU S390x KVM floating interrupt controller (flic)
+ *
+ * Copyright 2014 IBM Corp.
+ * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef __KVM_S390_FLIC_H
+#define __KVM_S390_FLIC_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_KVM_S390_FLIC "s390-flic"
+#define KVM_S390_FLIC(obj) \
+ OBJECT_CHECK(KVMS390FLICState, (obj), TYPE_KVM_S390_FLIC)
+
+typedef struct KVMS390FLICState {
+ SysBusDevice parent_obj;
+
+ uint32_t fd;
+} KVMS390FLICState;
+
+#ifdef CONFIG_KVM
+void s390_flic_init(void);
+#else
+static inline void s390_flic_init(void) { }
+#endif
+
+#endif /* __KVM_S390_FLIC_H */
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
index 35112d92b1..7ef16226df 100644
--- a/include/hw/s390x/sclp.h
+++ b/include/hw/s390x/sclp.h
@@ -161,30 +161,6 @@ static inline int sccb_data_len(SCCB *sccb)
return be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
}
-#define TYPE_DEVICE_S390_SCLP "s390-sclp-device"
-#define SCLP_S390_DEVICE(obj) \
- OBJECT_CHECK(S390SCLPDevice, (obj), TYPE_DEVICE_S390_SCLP)
-#define SCLP_S390_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(S390SCLPDeviceClass, (klass), \
- TYPE_DEVICE_S390_SCLP)
-#define SCLP_S390_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(S390SCLPDeviceClass, (obj), \
- TYPE_DEVICE_S390_SCLP)
-
-typedef struct SCLPEventFacility SCLPEventFacility;
-
-typedef struct S390SCLPDevice {
- SysBusDevice busdev;
- SCLPEventFacility *ef;
- void (*sclp_command_handler)(SCLPEventFacility *ef, SCCB *sccb,
- uint64_t code);
- bool (*event_pending)(SCLPEventFacility *ef);
-} S390SCLPDevice;
-
-typedef struct S390SCLPDeviceClass {
- DeviceClass qdev;
- int (*init)(S390SCLPDevice *sdev);
-} S390SCLPDeviceClass;
void s390_sclp_init(void);
void sclp_service_interrupt(uint32_t sccb);
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index bf6da3d632..e5fc39d504 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -31,7 +31,7 @@ typedef struct SCSISense {
uint8_t ascq;
} SCSISense;
-#define SCSI_SENSE_BUF_SIZE 96
+#define SCSI_SENSE_BUF_SIZE 252
struct SCSICommand {
uint8_t buf[SCSI_CMD_BUF_SIZE];
@@ -223,6 +223,8 @@ extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
/* Data Protection, Write Protected */
extern const struct SCSISense sense_code_WRITE_PROTECTED;
+/* Data Protection, Space Allocation Failed Write Protect */
+extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
#define SENSE_CODE(x) sense_code_ ## x
diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h
index e1f88bf9cf..e1818213b2 100644
--- a/include/hw/xen/xen.h
+++ b/include/hw/xen/xen.h
@@ -10,6 +10,7 @@
#include "hw/irq.h"
#include "qemu-common.h"
+#include "sysemu/qemumachine.h"
/* xen-machine.c */
enum xen_mode {
@@ -36,7 +37,7 @@ void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
qemu_irq *xen_interrupt_controller_init(void);
-int xen_init(void);
+int xen_init(QEMUMachine *machine);
int xen_hvm_init(MemoryRegion **ram_memory);
void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h
index 73c67b70c2..25193c943b 100644
--- a/include/qapi/qmp/qerror.h
+++ b/include/qapi/qmp/qerror.h
@@ -105,7 +105,7 @@ void qerror_report_err(Error *err);
ERROR_CLASS_GENERIC_ERROR, "Device '%s' does not support hotplugging"
#define QERR_DEVICE_NOT_ACTIVE \
- ERROR_CLASS_DEVICE_NOT_ACTIVE, "Device '%s' has not been activated"
+ ERROR_CLASS_DEVICE_NOT_ACTIVE, "No %s device has been activated"
#define QERR_DEVICE_NOT_ENCRYPTED \
ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not encrypted"
diff --git a/include/qapi/qmp/qjson.h b/include/qapi/qmp/qjson.h
index 73351ed6d6..ee4d31a46a 100644
--- a/include/qapi/qmp/qjson.h
+++ b/include/qapi/qmp/qjson.h
@@ -19,7 +19,7 @@
#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qstring.h"
-QObject *qobject_from_json(const char *string) GCC_FMT_ATTR(1, 0);
+QObject *qobject_from_json(const char *string);
QObject *qobject_from_jsonf(const char *string, ...) GCC_FMT_ATTR(1, 2);
QObject *qobject_from_jsonv(const char *string, va_list *ap) GCC_FMT_ATTR(1, 0);
diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h
index 437b8e0a9e..0cb7c05554 100644
--- a/include/qemu/bswap.h
+++ b/include/qemu/bswap.h
@@ -228,7 +228,7 @@ static inline int ldsb_p(const void *ptr)
return *(int8_t *)ptr;
}
-static inline void stb_p(void *ptr, int v)
+static inline void stb_p(void *ptr, uint8_t v)
{
*(uint8_t *)ptr = v;
}
@@ -300,12 +300,12 @@ static inline uint64_t ldq_le_p(const void *ptr)
return le_bswap(ldq_p(ptr), 64);
}
-static inline void stw_le_p(void *ptr, int v)
+static inline void stw_le_p(void *ptr, uint16_t v)
{
stw_p(ptr, le_bswap(v, 16));
}
-static inline void stl_le_p(void *ptr, int v)
+static inline void stl_le_p(void *ptr, uint32_t v)
{
stl_p(ptr, le_bswap(v, 32));
}
@@ -365,12 +365,12 @@ static inline uint64_t ldq_be_p(const void *ptr)
return be_bswap(ldq_p(ptr), 64);
}
-static inline void stw_be_p(void *ptr, int v)
+static inline void stw_be_p(void *ptr, uint16_t v)
{
stw_p(ptr, be_bswap(v, 16));
}
-static inline void stl_be_p(void *ptr, int v)
+static inline void stl_be_p(void *ptr, uint32_t v)
{
stl_p(ptr, be_bswap(v, 32));
}
diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
index de85d282d0..d4f21c947f 100644
--- a/include/qemu/host-utils.h
+++ b/include/qemu/host-utils.h
@@ -44,9 +44,37 @@ static inline void muls64(uint64_t *plow, uint64_t *phigh,
*plow = r;
*phigh = r >> 64;
}
+
+static inline int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor)
+{
+ if (divisor == 0) {
+ return 1;
+ } else {
+ __uint128_t dividend = ((__uint128_t)*phigh << 64) | *plow;
+ __uint128_t result = dividend / divisor;
+ *plow = result;
+ *phigh = dividend % divisor;
+ return result > UINT64_MAX;
+ }
+}
+
+static inline int divs128(int64_t *plow, int64_t *phigh, int64_t divisor)
+{
+ if (divisor == 0) {
+ return 1;
+ } else {
+ __int128_t dividend = ((__int128_t)*phigh << 64) | *plow;
+ __int128_t result = dividend / divisor;
+ *plow = result;
+ *phigh = dividend % divisor;
+ return result != *plow;
+ }
+}
#else
void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b);
void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
+int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor);
+int divs128(int64_t *plow, int64_t *phigh, int64_t divisor);
#endif
/**
@@ -217,7 +245,7 @@ static inline int ctz64(uint64_t val)
}
/**
- * ctz64 - count trailing ones in a 64-bit value.
+ * cto64 - count trailing ones in a 64-bit value.
* @val: The value to search
*
* Returns 64 if the value is -1.
diff --git a/include/qemu/thread.h b/include/qemu/thread.h
index 3e32c6531c..f7e3b9b290 100644
--- a/include/qemu/thread.h
+++ b/include/qemu/thread.h
@@ -52,12 +52,13 @@ void qemu_event_reset(QemuEvent *ev);
void qemu_event_wait(QemuEvent *ev);
void qemu_event_destroy(QemuEvent *ev);
-void qemu_thread_create(QemuThread *thread,
+void qemu_thread_create(QemuThread *thread, const char *name,
void *(*start_routine)(void *),
void *arg, int mode);
void *qemu_thread_join(QemuThread *thread);
void qemu_thread_get_self(QemuThread *thread);
bool qemu_thread_is_self(QemuThread *thread);
void qemu_thread_exit(void *retval);
+void qemu_thread_naming(bool enable);
#endif
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 367eda17d1..d734be8a40 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -28,7 +28,8 @@
#include "qemu/tls.h"
#include "qemu/typedefs.h"
-typedef int (*WriteCoreDumpFunction)(void *buf, size_t size, void *opaque);
+typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size,
+ void *opaque);
/**
* vaddr:
diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h
index 19fafb2cf9..efab7a32f3 100644
--- a/include/sysemu/dump.h
+++ b/include/sysemu/dump.h
@@ -14,12 +14,150 @@
#ifndef DUMP_H
#define DUMP_H
+#define MAKEDUMPFILE_SIGNATURE "makedumpfile"
+#define MAX_SIZE_MDF_HEADER (4096) /* max size of makedumpfile_header */
+#define TYPE_FLAT_HEADER (1) /* type of flattened format */
+#define VERSION_FLAT_HEADER (1) /* version of flattened format */
+#define END_FLAG_FLAT_HEADER (-1)
+
+#define ARCH_PFN_OFFSET (0)
+
+#define paddr_to_pfn(X, page_shift) \
+ (((unsigned long long)(X) >> (page_shift)) - ARCH_PFN_OFFSET)
+#define pfn_to_paddr(X, page_shift) \
+ (((unsigned long long)(X) + ARCH_PFN_OFFSET) << (page_shift))
+
+/*
+ * flag for compressed format
+ */
+#define DUMP_DH_COMPRESSED_ZLIB (0x1)
+#define DUMP_DH_COMPRESSED_LZO (0x2)
+#define DUMP_DH_COMPRESSED_SNAPPY (0x4)
+
+#define KDUMP_SIGNATURE "KDUMP "
+#define SIG_LEN (sizeof(KDUMP_SIGNATURE) - 1)
+#define PHYS_BASE (0)
+#define DUMP_LEVEL (1)
+#define DISKDUMP_HEADER_BLOCKS (1)
+#define BUFSIZE_BITMAP (TARGET_PAGE_SIZE)
+#define PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP)
+#define BUFSIZE_DATA_CACHE (TARGET_PAGE_SIZE * 4)
+
typedef struct ArchDumpInfo {
int d_machine; /* Architecture */
int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
int d_class; /* ELFCLASS32 or ELFCLASS64 */
} ArchDumpInfo;
+typedef struct QEMU_PACKED MakedumpfileHeader {
+ char signature[16]; /* = "makedumpfile" */
+ int64_t type;
+ int64_t version;
+} MakedumpfileHeader;
+
+typedef struct QEMU_PACKED MakedumpfileDataHeader {
+ int64_t offset;
+ int64_t buf_size;
+} MakedumpfileDataHeader;
+
+typedef struct QEMU_PACKED NewUtsname {
+ char sysname[65];
+ char nodename[65];
+ char release[65];
+ char version[65];
+ char machine[65];
+ char domainname[65];
+} NewUtsname;
+
+typedef struct QEMU_PACKED DiskDumpHeader32 {
+ char signature[SIG_LEN]; /* = "KDUMP " */
+ uint32_t header_version; /* Dump header version */
+ NewUtsname utsname; /* copy of system_utsname */
+ char timestamp[10]; /* Time stamp */
+ uint32_t status; /* Above flags */
+ uint32_t block_size; /* Size of a block in byte */
+ uint32_t sub_hdr_size; /* Size of arch dependent header in block */
+ uint32_t bitmap_blocks; /* Size of Memory bitmap in block */
+ uint32_t max_mapnr; /* = max_mapnr ,
+ obsoleted in header_version 6 */
+ uint32_t total_ram_blocks; /* Number of blocks should be written */
+ uint32_t device_blocks; /* Number of total blocks in dump device */
+ uint32_t written_blocks; /* Number of written blocks */
+ uint32_t current_cpu; /* CPU# which handles dump */
+ uint32_t nr_cpus; /* Number of CPUs */
+} DiskDumpHeader32;
+
+typedef struct QEMU_PACKED DiskDumpHeader64 {
+ char signature[SIG_LEN]; /* = "KDUMP " */
+ uint32_t header_version; /* Dump header version */
+ NewUtsname utsname; /* copy of system_utsname */
+ char timestamp[22]; /* Time stamp */
+ uint32_t status; /* Above flags */
+ uint32_t block_size; /* Size of a block in byte */
+ uint32_t sub_hdr_size; /* Size of arch dependent header in block */
+ uint32_t bitmap_blocks; /* Size of Memory bitmap in block */
+ uint32_t max_mapnr; /* = max_mapnr,
+ obsoleted in header_version 6 */
+ uint32_t total_ram_blocks; /* Number of blocks should be written */
+ uint32_t device_blocks; /* Number of total blocks in dump device */
+ uint32_t written_blocks; /* Number of written blocks */
+ uint32_t current_cpu; /* CPU# which handles dump */
+ uint32_t nr_cpus; /* Number of CPUs */
+} DiskDumpHeader64;
+
+typedef struct QEMU_PACKED KdumpSubHeader32 {
+ uint32_t phys_base;
+ uint32_t dump_level; /* header_version 1 and later */
+ uint32_t split; /* header_version 2 and later */
+ uint32_t start_pfn; /* header_version 2 and later,
+ obsoleted in header_version 6 */
+ uint32_t end_pfn; /* header_version 2 and later,
+ obsoleted in header_version 6 */
+ uint64_t offset_vmcoreinfo; /* header_version 3 and later */
+ uint32_t size_vmcoreinfo; /* header_version 3 and later */
+ uint64_t offset_note; /* header_version 4 and later */
+ uint32_t note_size; /* header_version 4 and later */
+ uint64_t offset_eraseinfo; /* header_version 5 and later */
+ uint32_t size_eraseinfo; /* header_version 5 and later */
+ uint64_t start_pfn_64; /* header_version 6 and later */
+ uint64_t end_pfn_64; /* header_version 6 and later */
+ uint64_t max_mapnr_64; /* header_version 6 and later */
+} KdumpSubHeader32;
+
+typedef struct QEMU_PACKED KdumpSubHeader64 {
+ uint64_t phys_base;
+ uint32_t dump_level; /* header_version 1 and later */
+ uint32_t split; /* header_version 2 and later */
+ uint64_t start_pfn; /* header_version 2 and later,
+ obsoleted in header_version 6 */
+ uint64_t end_pfn; /* header_version 2 and later,
+ obsoleted in header_version 6 */
+ uint64_t offset_vmcoreinfo; /* header_version 3 and later */
+ uint64_t size_vmcoreinfo; /* header_version 3 and later */
+ uint64_t offset_note; /* header_version 4 and later */
+ uint64_t note_size; /* header_version 4 and later */
+ uint64_t offset_eraseinfo; /* header_version 5 and later */
+ uint64_t size_eraseinfo; /* header_version 5 and later */
+ uint64_t start_pfn_64; /* header_version 6 and later */
+ uint64_t end_pfn_64; /* header_version 6 and later */
+ uint64_t max_mapnr_64; /* header_version 6 and later */
+} KdumpSubHeader64;
+
+typedef struct DataCache {
+ int fd; /* fd of the file where to write the cached data */
+ uint8_t *buf; /* buffer for cached data */
+ size_t buf_size; /* size of the buf */
+ size_t data_size; /* size of cached data in buf */
+ off_t offset; /* offset of the file */
+} DataCache;
+
+typedef struct QEMU_PACKED PageDescriptor {
+ uint64_t offset; /* the offset of the page data*/
+ uint32_t size; /* the size of this dump page */
+ uint32_t flags; /* flags */
+ uint64_t page_flags; /* page flags */
+} PageDescriptor;
+
struct GuestPhysBlockList; /* memory_mapping.h */
int cpu_get_dump_info(ArchDumpInfo *info,
const struct GuestPhysBlockList *guest_phys_blocks);
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index a02d67cd5a..ed01998aa8 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -18,6 +18,7 @@
#include "config-host.h"
#include "qemu/queue.h"
#include "qom/cpu.h"
+#include "sysemu/qemumachine.h"
#ifdef CONFIG_KVM
#include <linux/kvm.h>
@@ -152,7 +153,7 @@ extern KVMState *kvm_state;
/* external API */
-int kvm_init(void);
+int kvm_init(QEMUMachine *machine);
int kvm_has_sync_mmu(void);
int kvm_has_vcpu_events(void);
diff --git a/include/sysemu/qemumachine.h b/include/sysemu/qemumachine.h
new file mode 100644
index 0000000000..4cefd56b67
--- /dev/null
+++ b/include/sysemu/qemumachine.h
@@ -0,0 +1,16 @@
+/*
+ * QEMU Machine typedef
+ *
+ * Copyright Alexander Graf <agraf@suse.de>
+ *
+ * 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 QEMUMACHINE_H
+#define QEMUMACHINE_H
+
+typedef struct QEMUMachine QEMUMachine;
+
+#endif /* !QEMUMACHINE_H */
diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
index 28f4875112..e62281d4bf 100644
--- a/include/sysemu/qtest.h
+++ b/include/sysemu/qtest.h
@@ -16,6 +16,7 @@
#include "qemu-common.h"
#include "qapi/error.h"
+#include "sysemu/qemumachine.h"
extern bool qtest_allowed;
@@ -26,7 +27,7 @@ static inline bool qtest_enabled(void)
bool qtest_driver(void);
-int qtest_init_accel(void);
+int qtest_init_accel(QEMUMachine *machine);
void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp);
static inline int qtest_available(void)
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 495dae8c39..b90df9ada1 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -104,6 +104,7 @@ extern int autostart;
typedef enum {
VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
+ VGA_TCX, VGA_CG3,
} VGAInterfaceType;
extern int vga_interface_type;
diff --git a/include/ui/console.h b/include/ui/console.h
index 4156a876e1..08a38eab13 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -14,6 +14,8 @@
#define MOUSE_EVENT_LBUTTON 0x01
#define MOUSE_EVENT_RBUTTON 0x02
#define MOUSE_EVENT_MBUTTON 0x04
+#define MOUSE_EVENT_WHEELUP 0x08
+#define MOUSE_EVENT_WHEELDN 0x10
/* identical to the ps/2 keyboard bits */
#define QEMU_SCROLL_LOCK_LED (1 << 0)
@@ -44,17 +46,7 @@ void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry);
QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque);
void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry);
-void kbd_put_keycode(int keycode);
void kbd_put_ledstate(int ledstate);
-void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
-
-/* Does the current mouse generate absolute events */
-int kbd_mouse_is_absolute(void);
-void qemu_add_mouse_mode_change_notifier(Notifier *notify);
-void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
-
-/* Of all the mice, is there one that generates absolute events */
-int kbd_mouse_has_absolute(void);
struct MouseTransformInfo {
/* Touchscreen resolution */
@@ -128,6 +120,14 @@ struct DisplaySurface {
struct PixelFormat pf;
};
+typedef struct QemuUIInfo {
+ /* geometry */
+ int xoff;
+ int yoff;
+ uint32_t width;
+ uint32_t height;
+} QemuUIInfo;
+
/* cursor data format is 32bit RGBA */
typedef struct QEMUCursor {
int width, height;
@@ -212,6 +212,8 @@ void update_displaychangelistener(DisplayChangeListener *dcl,
uint64_t interval);
void unregister_displaychangelistener(DisplayChangeListener *dcl);
+int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info);
+
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
void dpy_gfx_replace_surface(QemuConsole *con,
DisplaySurface *surface);
@@ -274,9 +276,10 @@ typedef struct GraphicHwOps {
void (*gfx_update)(void *opaque);
void (*text_update)(void *opaque, console_ch_t *text);
void (*update_interval)(void *opaque, uint64_t interval);
+ int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
} GraphicHwOps;
-QemuConsole *graphic_console_init(DeviceState *dev,
+QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
const GraphicHwOps *ops,
void *opaque);
@@ -285,10 +288,15 @@ void graphic_hw_invalidate(QemuConsole *con);
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
QemuConsole *qemu_console_lookup_by_index(unsigned int index);
-QemuConsole *qemu_console_lookup_by_device(DeviceState *dev);
+QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
bool qemu_console_is_visible(QemuConsole *con);
bool qemu_console_is_graphic(QemuConsole *con);
bool qemu_console_is_fixedsize(QemuConsole *con);
+int qemu_console_get_index(QemuConsole *con);
+uint32_t qemu_console_get_head(QemuConsole *con);
+QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con);
+int qemu_console_get_width(QemuConsole *con, int fallback);
+int qemu_console_get_height(QemuConsole *con, int fallback);
void text_consoles_set_display(DisplayState *ds);
void console_select(unsigned int index);
@@ -334,7 +342,6 @@ void curses_display_init(DisplayState *ds, int full_screen);
/* input.c */
int index_from_key(const char *key);
-int index_from_keycode(int code);
/* gtk.c */
void early_gtk_display_init(void);
diff --git a/include/ui/input.h b/include/ui/input.h
new file mode 100644
index 0000000000..4976f3da2c
--- /dev/null
+++ b/include/ui/input.h
@@ -0,0 +1,56 @@
+#ifndef INPUT_H
+#define INPUT_H
+
+#include "qapi-types.h"
+
+#define INPUT_EVENT_MASK_KEY (1<<INPUT_EVENT_KIND_KEY)
+#define INPUT_EVENT_MASK_BTN (1<<INPUT_EVENT_KIND_BTN)
+#define INPUT_EVENT_MASK_REL (1<<INPUT_EVENT_KIND_REL)
+#define INPUT_EVENT_MASK_ABS (1<<INPUT_EVENT_KIND_ABS)
+
+#define INPUT_EVENT_ABS_SIZE 0x8000
+
+typedef struct QemuInputHandler QemuInputHandler;
+typedef struct QemuInputHandlerState QemuInputHandlerState;
+
+typedef void (*QemuInputHandlerEvent)(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt);
+typedef void (*QemuInputHandlerSync)(DeviceState *dev);
+
+struct QemuInputHandler {
+ const char *name;
+ uint32_t mask;
+ QemuInputHandlerEvent event;
+ QemuInputHandlerSync sync;
+};
+
+QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
+ QemuInputHandler *handler);
+void qemu_input_handler_activate(QemuInputHandlerState *s);
+void qemu_input_handler_unregister(QemuInputHandlerState *s);
+void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
+void qemu_input_event_sync(void);
+
+InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
+void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
+void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down);
+void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down);
+
+InputEvent *qemu_input_event_new_btn(InputButton btn, bool down);
+void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down);
+void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
+ uint32_t button_old, uint32_t button_new);
+
+bool qemu_input_is_absolute(void);
+int qemu_input_scale_axis(int value, int size_in, int size_out);
+InputEvent *qemu_input_event_new_move(InputEventKind kind,
+ InputAxis axis, int value);
+void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value);
+void qemu_input_queue_abs(QemuConsole *src, InputAxis axis,
+ int value, int size);
+
+void qemu_input_check_mode_change(void);
+void qemu_add_mouse_mode_change_notifier(Notifier *notify);
+void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
+
+#endif /* INPUT_H */
diff --git a/kvm-all.c b/kvm-all.c
index f299532e27..82a91199e1 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -36,6 +36,8 @@
#include "qemu/event_notifier.h"
#include "trace.h"
+#include "hw/boards.h"
+
/* This check must be after config-host.h is included */
#ifdef CONFIG_EVENTFD
#include <sys/eventfd.h>
@@ -1339,7 +1341,7 @@ static int kvm_max_vcpus(KVMState *s)
return (ret) ? ret : kvm_recommended_vcpus(s);
}
-int kvm_init(void)
+int kvm_init(QEMUMachine *machine)
{
static const char upgrade_note[] =
"Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
@@ -1356,7 +1358,8 @@ int kvm_init(void)
KVMState *s;
const KVMCapabilityInfo *missing_cap;
int ret;
- int i;
+ int i, type = 0;
+ const char *kvm_type;
s = g_malloc0(sizeof(KVMState));
@@ -1429,8 +1432,16 @@ int kvm_init(void)
nc++;
}
+ kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type");
+ if (machine->kvm_type) {
+ type = machine->kvm_type(kvm_type);
+ } else if (kvm_type) {
+ fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type);
+ goto err;
+ }
+
do {
- ret = kvm_ioctl(s, KVM_CREATE_VM, 0);
+ ret = kvm_ioctl(s, KVM_CREATE_VM, type);
} while (ret == -EINTR);
if (ret < 0) {
diff --git a/kvm-stub.c b/kvm-stub.c
index e979f76d07..4ef084e84a 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -14,6 +14,7 @@
#include "hw/hw.h"
#include "cpu.h"
#include "sysemu/kvm.h"
+#include "sysemu/qemumachine.h"
#ifndef CONFIG_USER_ONLY
#include "hw/pci/msi.h"
@@ -34,7 +35,7 @@ int kvm_init_vcpu(CPUState *cpu)
return -ENOSYS;
}
-int kvm_init(void)
+int kvm_init(QEMUMachine *machine)
{
return -ENOSYS;
}
diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
index 24f7088ecf..3477ab3e1b 100644
--- a/libcacard/vscclient.c
+++ b/libcacard/vscclient.c
@@ -269,7 +269,7 @@ on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming)
send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0);
/* launch the event_thread. This will trigger reader adds for all the
* existing readers */
- qemu_thread_create(&thread_id, event_thread, NULL, 0);
+ qemu_thread_create(&thread_id, "vsc/event", event_thread, NULL, 0);
return 0;
}
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index d25da598ec..cb4c1eb8a0 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -16,6 +16,22 @@
#define __KVM_S390
+/* Device control API: s390-specific devices */
+#define KVM_DEV_FLIC_GET_ALL_IRQS 1
+#define KVM_DEV_FLIC_ENQUEUE 2
+#define KVM_DEV_FLIC_CLEAR_IRQS 3
+#define KVM_DEV_FLIC_APF_ENABLE 4
+#define KVM_DEV_FLIC_APF_DISABLE_WAIT 5
+/*
+ * We can have up to 4*64k pending subchannels + 8 adapter interrupts,
+ * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
+ * There are also sclp and machine checks. This gives us
+ * sizeof(kvm_s390_irq)*(4*65536+8+64*64+1+1) = 72 * 266250 = 19170000
+ * Lets round up to 8192 pages.
+ */
+#define KVM_S390_MAX_FLOAT_IRQS 266250
+#define KVM_S390_FLIC_MAX_BUFFER 0x2000000
+
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* general purpose regs for s390 */
@@ -57,4 +73,7 @@ struct kvm_sync_regs {
#define KVM_REG_S390_EPOCHDIFF (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x2)
#define KVM_REG_S390_CPU_TIMER (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x3)
#define KVM_REG_S390_CLOCK_COMP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x4)
+#define KVM_REG_S390_PFTOKEN (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x5)
+#define KVM_REG_S390_PFCOMPARE (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x6)
+#define KVM_REG_S390_PFSELECT (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x7)
#endif
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 77ad35cd67..e27a4b33cf 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -413,6 +413,8 @@ struct kvm_s390_psw {
#define KVM_S390_PROGRAM_INT 0xfffe0001u
#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u
#define KVM_S390_RESTART 0xfffe0003u
+#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
+#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
#define KVM_S390_MCHK 0xfffe1000u
#define KVM_S390_INT_VIRTIO 0xffff2603u
#define KVM_S390_INT_SERVICE 0xffff2401u
@@ -434,6 +436,69 @@ struct kvm_s390_interrupt {
__u64 parm64;
};
+struct kvm_s390_io_info {
+ __u16 subchannel_id;
+ __u16 subchannel_nr;
+ __u32 io_int_parm;
+ __u32 io_int_word;
+};
+
+struct kvm_s390_ext_info {
+ __u32 ext_params;
+ __u32 pad;
+ __u64 ext_params2;
+};
+
+struct kvm_s390_pgm_info {
+ __u64 trans_exc_code;
+ __u64 mon_code;
+ __u64 per_address;
+ __u32 data_exc_code;
+ __u16 code;
+ __u16 mon_class_nr;
+ __u8 per_code;
+ __u8 per_atmid;
+ __u8 exc_access_id;
+ __u8 per_access_id;
+ __u8 op_access_id;
+ __u8 pad[3];
+};
+
+struct kvm_s390_prefix_info {
+ __u32 address;
+};
+
+struct kvm_s390_extcall_info {
+ __u16 code;
+};
+
+struct kvm_s390_emerg_info {
+ __u16 code;
+};
+
+struct kvm_s390_mchk_info {
+ __u64 cr14;
+ __u64 mcic;
+ __u64 failing_storage_address;
+ __u32 ext_damage_code;
+ __u32 pad;
+ __u8 fixed_logout[16];
+};
+
+struct kvm_s390_irq {
+ __u64 type;
+ union {
+ struct kvm_s390_io_info io;
+ struct kvm_s390_ext_info ext;
+ struct kvm_s390_pgm_info pgm;
+ struct kvm_s390_emerg_info emerg;
+ struct kvm_s390_extcall_info extcall;
+ struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_mchk_info mchk;
+ char reserved[64];
+ } u;
+};
+
/* for KVM_SET_GUEST_DEBUG */
#define KVM_GUESTDBG_ENABLE 0x00000001
@@ -855,6 +920,7 @@ struct kvm_device_attr {
#define KVM_DEV_VFIO_GROUP_ADD 1
#define KVM_DEV_VFIO_GROUP_DEL 2
#define KVM_DEV_TYPE_ARM_VGIC_V2 5
+#define KVM_DEV_TYPE_FLIC 6
/*
* ioctls for VM fds
diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h
index 15a0100335..ed13d9a718 100644
--- a/linux-user/alpha/syscall.h
+++ b/linux-user/alpha/syscall.h
@@ -39,6 +39,7 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "alpha"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#undef TARGET_EDEADLK
#define TARGET_EDEADLK 11
diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h
index 73f29314f6..ce2c2a8ed0 100644
--- a/linux-user/arm/syscall.h
+++ b/linux-user/arm/syscall.h
@@ -40,5 +40,6 @@ struct target_pt_regs {
#else
#define UNAME_MACHINE "armv5tel"
#endif
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h
index 832ee64bd8..f5783c0557 100644
--- a/linux-user/cris/syscall.h
+++ b/linux-user/cris/syscall.h
@@ -1,8 +1,8 @@
#ifndef CRIS_SYSCALL_H
#define CRIS_SYSCALL_H 1
-
#define UNAME_MACHINE "cris"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
/* pt_regs not only specifices the format in the user-struct during
* ptrace but is also the frame format used in the kernel prologue/epilogues
diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h
index 12b8c3b672..9bfc1ad8f7 100644
--- a/linux-user/i386/syscall.h
+++ b/linux-user/i386/syscall.h
@@ -144,5 +144,6 @@ struct target_vm86plus_struct {
};
#define UNAME_MACHINE "i686"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/syscall.h
index 26187930db..889eaf7323 100644
--- a/linux-user/m68k/syscall.h
+++ b/linux-user/m68k/syscall.h
@@ -15,7 +15,7 @@ struct target_pt_regs {
uint16_t __fill;
};
-
#define UNAME_MACHINE "m68k"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
void do_m68k_simcall(CPUM68KState *, int);
diff --git a/linux-user/main.c b/linux-user/main.c
index 919297736c..dee10841c3 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1492,7 +1492,7 @@ static int do_store_exclusive(CPUPPCState *env)
{
target_ulong addr;
target_ulong page_addr;
- target_ulong val;
+ target_ulong val, val2 __attribute__((unused));
int flags;
int segv = 0;
@@ -1515,6 +1515,13 @@ static int do_store_exclusive(CPUPPCState *env)
case 4: segv = get_user_u32(val, addr); break;
#if defined(TARGET_PPC64)
case 8: segv = get_user_u64(val, addr); break;
+ case 16: {
+ segv = get_user_u64(val, addr);
+ if (!segv) {
+ segv = get_user_u64(val2, addr + 8);
+ }
+ break;
+ }
#endif
default: abort();
}
@@ -1526,6 +1533,15 @@ static int do_store_exclusive(CPUPPCState *env)
case 4: segv = put_user_u32(val, addr); break;
#if defined(TARGET_PPC64)
case 8: segv = put_user_u64(val, addr); break;
+ case 16: {
+ if (val2 == env->reserve_val2) {
+ segv = put_user_u64(val, addr);
+ if (!segv) {
+ segv = put_user_u64(val2, addr + 8);
+ }
+ }
+ break;
+ }
#endif
default: abort();
}
@@ -2384,6 +2400,10 @@ static int do_break(CPUMIPSState *env, target_siginfo_t *info,
ret = 0;
break;
default:
+ info->si_signo = TARGET_SIGTRAP;
+ info->si_errno = 0;
+ queue_signal(env, info->si_signo, &*info);
+ ret = 0;
break;
}
diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h
index d550989d5e..5b5f6b447d 100644
--- a/linux-user/microblaze/syscall.h
+++ b/linux-user/microblaze/syscall.h
@@ -1,8 +1,8 @@
#ifndef MICROBLAZE_SYSCALLS_H
#define MICROBLAZE_SYSCALLS_H 1
-
#define UNAME_MACHINE "microblaze"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
/* We use microblaze_reg_t to keep things similar to the kernel sources. */
typedef uint32_t microblaze_reg_t;
diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h
index 9d437d918b..5bc56962a4 100644
--- a/linux-user/mips/syscall.h
+++ b/linux-user/mips/syscall.h
@@ -225,5 +225,6 @@ struct target_pt_regs {
#define TARGET_QEMU_ESIGRETURN 255
#define UNAME_MACHINE "mips"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
index 1710f766e2..a7f5a5802a 100644
--- a/linux-user/mips64/syscall.h
+++ b/linux-user/mips64/syscall.h
@@ -222,5 +222,6 @@ struct target_pt_regs {
#define TARGET_QEMU_ESIGRETURN 255
#define UNAME_MACHINE "mips64"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/openrisc/syscall.h b/linux-user/openrisc/syscall.h
index bdbb577fc3..c3b36da83c 100644
--- a/linux-user/openrisc/syscall.h
+++ b/linux-user/openrisc/syscall.h
@@ -22,3 +22,4 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "openrisc"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h
index ba36acbc33..6514c637a5 100644
--- a/linux-user/ppc/syscall.h
+++ b/linux-user/ppc/syscall.h
@@ -62,5 +62,6 @@ struct target_revectored_struct {
#else
#define UNAME_MACHINE "ppc"
#endif
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#define TARGET_CLONE_BACKWARDS
diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h
index e5ce30b667..aaad512d4d 100644
--- a/linux-user/s390x/syscall.h
+++ b/linux-user/s390x/syscall.h
@@ -21,5 +21,6 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "s390x"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#define TARGET_CLONE_BACKWARDS2
diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h
index 014bf58fc3..ccd2216e38 100644
--- a/linux-user/sh4/syscall.h
+++ b/linux-user/sh4/syscall.h
@@ -10,3 +10,4 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "sh4"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 04638e2ead..c8a1da0749 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1233,8 +1233,14 @@ static int target_restore_sigframe(CPUARMState *env,
return 1;
}
- for (i = 0; i < 32 * 2; i++) {
- __get_user(env->vfp.regs[i], &aux->fpsimd.vregs[i]);
+ for (i = 0; i < 32; i++) {
+#ifdef TARGET_WORDS_BIGENDIAN
+ __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
+ __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
+#else
+ __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
+ __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
+#endif
}
__get_user(fpsr, &aux->fpsimd.fpsr);
vfp_set_fpsr(env, fpsr);
@@ -1267,7 +1273,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
CPUARMState *env)
{
struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
+ abi_ulong frame_addr, return_addr;
frame_addr = get_sigframe(ka, env);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
@@ -1284,15 +1290,19 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
__put_user(target_sigaltstack_used.ss_size,
&frame->uc.tuc_stack.ss_size);
target_setup_sigframe(frame, env, set);
- /* mov x8,#__NR_rt_sigreturn; svc #0 */
- __put_user(0xd2801168, &frame->tramp[0]);
- __put_user(0xd4000001, &frame->tramp[1]);
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ return_addr = ka->sa_restorer;
+ } else {
+ /* mov x8,#__NR_rt_sigreturn; svc #0 */
+ __put_user(0xd2801168, &frame->tramp[0]);
+ __put_user(0xd4000001, &frame->tramp[1]);
+ return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
+ }
env->xregs[0] = usig;
env->xregs[31] = frame_addr;
env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
env->pc = ka->_sa_handler;
- env->xregs[30] = env->xregs[31] +
- offsetof(struct target_rt_sigframe, tramp);
+ env->xregs[30] = return_addr;
if (info) {
if (copy_siginfo_to_user(&frame->info, info)) {
goto give_sigsegv;
diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h
index 4cd64bf41d..9549ea0a2f 100644
--- a/linux-user/sparc/syscall.h
+++ b/linux-user/sparc/syscall.h
@@ -7,6 +7,7 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "sun4"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
/* 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
diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h
index e60bf311c0..82b1680cb6 100644
--- a/linux-user/sparc64/syscall.h
+++ b/linux-user/sparc64/syscall.h
@@ -8,6 +8,7 @@ struct target_pt_regs {
};
#define UNAME_MACHINE "sun4u"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
/* 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
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1407b7a546..e2c10cc0bd 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1904,23 +1904,16 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr,
return get_errno(connect(sockfd, addr, addrlen));
}
-/* do_sendrecvmsg() Must return target values and target errnos. */
-static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
- int flags, int send)
+/* do_sendrecvmsg_locked() Must return target values and target errnos. */
+static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
+ int flags, int send)
{
abi_long ret, len;
- struct target_msghdr *msgp;
struct msghdr msg;
int count;
struct iovec *vec;
abi_ulong target_vec;
- /* FIXME */
- if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
- msgp,
- target_msg,
- send ? 1 : 0))
- return -TARGET_EFAULT;
if (msgp->msg_name) {
msg.msg_namelen = tswap32(msgp->msg_namelen);
msg.msg_name = alloca(msg.msg_namelen);
@@ -1975,10 +1968,75 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
out:
unlock_iovec(vec, target_vec, count, !send);
out2:
+ return ret;
+}
+
+static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
+ int flags, int send)
+{
+ abi_long ret;
+ struct target_msghdr *msgp;
+
+ if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
+ msgp,
+ target_msg,
+ send ? 1 : 0)) {
+ return -TARGET_EFAULT;
+ }
+ ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
unlock_user_struct(msgp, target_msg, send ? 0 : 1);
return ret;
}
+#ifdef TARGET_NR_sendmmsg
+/* We don't rely on the C library to have sendmmsg/recvmmsg support,
+ * so it might not have this *mmsg-specific flag either.
+ */
+#ifndef MSG_WAITFORONE
+#define MSG_WAITFORONE 0x10000
+#endif
+
+static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
+ unsigned int vlen, unsigned int flags,
+ int send)
+{
+ struct target_mmsghdr *mmsgp;
+ abi_long ret = 0;
+ int i;
+
+ if (vlen > UIO_MAXIOV) {
+ vlen = UIO_MAXIOV;
+ }
+
+ mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1);
+ if (!mmsgp) {
+ return -TARGET_EFAULT;
+ }
+
+ for (i = 0; i < vlen; i++) {
+ ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send);
+ if (is_error(ret)) {
+ break;
+ }
+ mmsgp[i].msg_len = tswap32(ret);
+ /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
+ if (flags & MSG_WAITFORONE) {
+ flags |= MSG_DONTWAIT;
+ }
+ }
+
+ unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i);
+
+ /* Return number of datagrams sent if we sent any at all;
+ * otherwise return the error.
+ */
+ if (i) {
+ return i;
+ }
+ return ret;
+}
+#endif
+
/* If we don't have a system accept4() then just call accept.
* The callsites to do_accept4() will ensure that they don't
* pass a non-zero flags argument in this config.
@@ -4528,6 +4586,9 @@ static inline int tswapid(int id)
{
return tswap16(id);
}
+
+#define put_user_id(x, gaddr) put_user_u16(x, gaddr)
+
#else /* !USE_UID16 */
static inline int high2lowuid(int uid)
{
@@ -4549,6 +4610,9 @@ static inline int tswapid(int id)
{
return tswap32(id);
}
+
+#define put_user_id(x, gaddr) put_user_u32(x, gaddr)
+
#endif /* USE_UID16 */
void syscall_init(void)
@@ -6121,11 +6185,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
puts = NULL;
}
ret = get_errno(sigtimedwait(&set, &uinfo, puts));
- if (!is_error(ret) && arg2) {
- if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0)))
- goto efault;
- host_to_target_siginfo(p, &uinfo);
- unlock_user(p, arg2, sizeof(target_siginfo_t));
+ if (!is_error(ret)) {
+ if (arg2) {
+ p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
+ 0);
+ if (!p) {
+ goto efault;
+ }
+ host_to_target_siginfo(p, &uinfo);
+ unlock_user(p, arg2, sizeof(target_siginfo_t));
+ }
+ ret = host_to_target_signal(ret);
}
}
break;
@@ -6710,6 +6780,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
break;
#endif
+#ifdef TARGET_NR_sendmmsg
+ case TARGET_NR_sendmmsg:
+ ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
+ break;
+ case TARGET_NR_recvmmsg:
+ ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
+ break;
+#endif
#ifdef TARGET_NR_sendto
case TARGET_NR_sendto:
ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
@@ -7805,9 +7883,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
uid_t ruid, euid, suid;
ret = get_errno(getresuid(&ruid, &euid, &suid));
if (!is_error(ret)) {
- if (put_user_u16(high2lowuid(ruid), arg1)
- || put_user_u16(high2lowuid(euid), arg2)
- || put_user_u16(high2lowuid(suid), arg3))
+ if (put_user_id(high2lowuid(ruid), arg1)
+ || put_user_id(high2lowuid(euid), arg2)
+ || put_user_id(high2lowuid(suid), arg3))
goto efault;
}
}
@@ -7826,9 +7904,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
gid_t rgid, egid, sgid;
ret = get_errno(getresgid(&rgid, &egid, &sgid));
if (!is_error(ret)) {
- if (put_user_u16(high2lowgid(rgid), arg1)
- || put_user_u16(high2lowgid(egid), arg2)
- || put_user_u16(high2lowgid(sgid), arg3))
+ if (put_user_id(high2lowgid(rgid), arg1)
+ || put_user_id(high2lowgid(egid), arg2)
+ || put_user_id(high2lowgid(sgid), arg3))
goto efault;
}
}
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 3c8869e073..732c9e3dbb 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -53,7 +53,8 @@
#define TARGET_IOC_NRBITS 8
#define TARGET_IOC_TYPEBITS 8
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
+#if defined(TARGET_I386) || (defined(TARGET_ARM) && defined(TARGET_ABI32)) \
+ || defined(TARGET_SPARC) \
|| defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
/* 16 bit uid wrappers emulation */
#define USE_UID16
@@ -239,6 +240,10 @@ __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cms
return __cmsg;
}
+struct target_mmsghdr {
+ struct target_msghdr msg_hdr; /* Message header */
+ unsigned int msg_len; /* Number of bytes transmitted */
+};
struct target_rusage {
struct target_timeval ru_utime; /* user time used */
diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h
index 010cdd896e..f7e55254cf 100644
--- a/linux-user/unicore32/syscall.h
+++ b/linux-user/unicore32/syscall.h
@@ -51,5 +51,6 @@ struct target_pt_regs {
#define UC32_SYSCALL_NR_set_tls (UC32_SYSCALL_ARCH_BASE + 5)
#define UNAME_MACHINE "UniCore-II"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#endif /* __UC32_SYSCALL_H__ */
diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h
index 81314cfae6..e03b5a0cfc 100644
--- a/linux-user/x86_64/syscall.h
+++ b/linux-user/x86_64/syscall.h
@@ -91,6 +91,7 @@ struct target_msqid64_ds {
};
#define UNAME_MACHINE "x86_64"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
#define TARGET_ARCH_SET_GS 0x1001
#define TARGET_ARCH_SET_FS 0x1002
diff --git a/memory.c b/memory.c
index 59ecc28401..3f1df238e2 100644
--- a/memory.c
+++ b/memory.c
@@ -1562,7 +1562,7 @@ static FlatRange *flatview_lookup(FlatView *view, AddrRange addr)
bool memory_region_present(MemoryRegion *parent, hwaddr addr)
{
MemoryRegion *mr = memory_region_find(parent, addr, 1).mr;
- if (!mr) {
+ if (!mr || (mr == parent)) {
return false;
}
memory_region_unref(mr);
diff --git a/migration.c b/migration.c
index 14235b280a..00f465ea46 100644
--- a/migration.c
+++ b/migration.c
@@ -695,6 +695,6 @@ void migrate_fd_connect(MigrationState *s)
/* Notify before starting migration thread */
notifier_list_notify(&migration_state_notifiers, s);
- qemu_thread_create(&s->thread, migration_thread, s,
+ qemu_thread_create(&s->thread, "migration", migration_thread, s,
QEMU_THREAD_JOINABLE);
}
diff --git a/monitor.c b/monitor.c
index aebcbd8beb..342e83baea 100644
--- a/monitor.c
+++ b/monitor.c
@@ -39,6 +39,7 @@
#include "monitor/monitor.h"
#include "qemu/readline.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "sysemu/blockdev.h"
#include "audio/audio.h"
#include "disas/disas.h"
@@ -1463,23 +1464,43 @@ static int mouse_button_state;
static void do_mouse_move(Monitor *mon, const QDict *qdict)
{
- int dx, dy, dz;
+ int dx, dy, dz, button;
const char *dx_str = qdict_get_str(qdict, "dx_str");
const char *dy_str = qdict_get_str(qdict, "dy_str");
const char *dz_str = qdict_get_try_str(qdict, "dz_str");
+
dx = strtol(dx_str, NULL, 0);
dy = strtol(dy_str, NULL, 0);
- dz = 0;
- if (dz_str)
+ qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
+ qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
+
+ if (dz_str) {
dz = strtol(dz_str, NULL, 0);
- kbd_mouse_event(dx, dy, dz, mouse_button_state);
+ if (dz != 0) {
+ button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
+ qemu_input_queue_btn(NULL, button, true);
+ qemu_input_event_sync();
+ qemu_input_queue_btn(NULL, button, false);
+ }
+ }
+ qemu_input_event_sync();
}
static void do_mouse_button(Monitor *mon, const QDict *qdict)
{
+ static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
+ [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
+ [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
+ };
int button_state = qdict_get_int(qdict, "button_state");
+
+ if (mouse_button_state == button_state) {
+ return;
+ }
+ qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state);
+ qemu_input_event_sync();
mouse_button_state = button_state;
- kbd_mouse_event(0, 0, 0, mouse_button_state);
}
static void do_ioport_read(Monitor *mon, const QDict *qdict)
@@ -2021,10 +2042,6 @@ int64_t dev_time;
static void do_info_profile(Monitor *mon, const QDict *qdict)
{
- int64_t total;
- total = qemu_time;
- if (total == 0)
- total = 1;
monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n",
dev_time, dev_time / (double)get_ticks_per_sec());
monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n",
diff --git a/pc-bios/QEMU,cgthree.bin b/pc-bios/QEMU,cgthree.bin
new file mode 100644
index 0000000000..6fec946207
--- /dev/null
+++ b/pc-bios/QEMU,cgthree.bin
Binary files differ
diff --git a/pc-bios/README b/pc-bios/README
index f1900686dc..2bb6357ea6 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -11,8 +11,8 @@
firmware implementation. The goal is to implement a 100% IEEE
1275-1994 (referred to as Open Firmware) compliant firmware.
The included images for PowerPC (for 32 and 64 bit PPC CPUs),
- Sparc32 (including QEMU,tcx.bin) and Sparc64 are built from OpenBIOS SVN
- revision 1246.
+ Sparc32 (including QEMU,tcx.bin and QEMU,cgthree.bin) and Sparc64 are built
+ from OpenBIOS SVN revision 1280.
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index f4a3a396c4..8a213894be 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index bb7cdfb4ec..d4d00e501f 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 46b4fddd08..4182052d65 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 6727f0ca39..f6223e77c2 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index c5d533231b..5c33766533 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -10,7 +10,6 @@
#include "s390-ccw.h"
-struct subchannel_id blk_schid;
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
uint64_t boot_value;
@@ -23,13 +22,13 @@ void virtio_panic(const char *string)
static void virtio_setup(uint64_t dev_info)
{
+ struct subchannel_id blk_schid = { .one = 1 };
struct schib schib;
int i;
int r;
bool found = false;
bool check_devno = false;
uint16_t dev_no = -1;
- blk_schid.one = 1;
if (dev_info != -1) {
check_devno = true;
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 4d6e48fcbe..a46914dd68 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -124,6 +124,7 @@ static void vring_init(struct vring *vr, unsigned int num, void *p,
vr->used->flags = VRING_USED_F_NO_NOTIFY;
vr->used->idx = 0;
vr->used_idx = 0;
+ vr->next_idx = 0;
debug_print_addr("init vr", vr);
}
diff --git a/qapi-schema.json b/qapi-schema.json
index ac8ad24966..6c381b7306 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2795,6 +2795,24 @@
{ 'command': 'device_del', 'data': {'id': 'str'} }
##
+# @DumpGuestMemoryFormat:
+#
+# An enumeration of guest-memory-dump's format.
+#
+# @elf: elf format
+#
+# @kdump-zlib: kdump-compressed format with zlib-compressed
+#
+# @kdump-lzo: kdump-compressed format with lzo-compressed
+#
+# @kdump-snappy: kdump-compressed format with snappy-compressed
+#
+# Since: 2.0
+##
+{ 'enum': 'DumpGuestMemoryFormat',
+ 'data': [ 'elf', 'kdump-zlib', 'kdump-lzo', 'kdump-snappy' ] }
+
+##
# @dump-guest-memory
#
# Dump guest's memory to vmcore. It is a synchronous operation that can take
@@ -2830,13 +2848,42 @@
# want to dump all guest's memory, please specify the start @begin
# and @length
#
+# @format: #optional if specified, the format of guest memory dump. But non-elf
+# format is conflict with paging and filter, ie. @paging, @begin and
+# @length is not allowed to be specified with non-elf @format at the
+# same time (since 2.0)
+#
# Returns: nothing on success
#
# Since: 1.2
##
{ 'command': 'dump-guest-memory',
'data': { 'paging': 'bool', 'protocol': 'str', '*begin': 'int',
- '*length': 'int' } }
+ '*length': 'int', '*format': 'DumpGuestMemoryFormat' } }
+
+##
+# @DumpGuestMemoryCapability:
+#
+# A list of the available formats for dump-guest-memory
+#
+# Since: 2.0
+##
+{ 'type': 'DumpGuestMemoryCapability',
+ 'data': {
+ 'formats': ['DumpGuestMemoryFormat'] } }
+
+##
+# @query-dump-guest-memory-capability:
+#
+# Returns the available formats for dump-guest-memory
+#
+# Returns: A @DumpGuestMemoryCapability object listing available formats for
+# dump-guest-memory
+#
+# Since: 2.0
+##
+{ 'command': 'query-dump-guest-memory-capability',
+ 'returns': 'DumpGuestMemoryCapability' }
##
# @netdev_add:
@@ -3508,9 +3555,12 @@
# This is used by the send-key command.
#
# Since: 1.3.0
+#
+# 'unmapped' and 'pause' since 2.0
##
{ 'enum': 'QKeyCode',
- 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl',
+ 'data': [ 'unmapped',
+ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl',
'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8',
'9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e',
'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right',
@@ -3524,7 +3574,7 @@
'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end',
'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again',
'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut',
- 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] }
+ 'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause' ] }
##
# @KeyValue
@@ -4436,10 +4486,11 @@
# Driver specific block device options for Quorum
#
# @blkverify: #optional true if the driver must print content mismatch
+# set to false by default
#
-# @children: the children block device to use
+# @children: the children block devices to use
#
-# @vote_threshold: the vote limit under which a read will fail
+# @vote-threshold: the vote limit under which a read will fail
#
# Since: 2.0
##
@@ -4518,3 +4569,79 @@
# Since: 1.7
##
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
+
+##
+# @InputButton
+#
+# Button of a pointer input device (mouse, tablet).
+#
+# Since: 2.0
+##
+{ 'enum' : 'InputButton',
+ 'data' : [ 'Left', 'Middle', 'Right', 'WheelUp', 'WheelDown' ] }
+
+##
+# @InputButton
+#
+# Position axis of a pointer input device (mouse, tablet).
+#
+# Since: 2.0
+##
+{ 'enum' : 'InputAxis',
+ 'data' : [ 'X', 'Y' ] }
+
+##
+# @InputKeyEvent
+#
+# Keyboard input event.
+#
+# @key: Which key this event is for.
+# @down: True for key-down and false for key-up events.
+#
+# Since: 2.0
+##
+{ 'type' : 'InputKeyEvent',
+ 'data' : { 'key' : 'KeyValue',
+ 'down' : 'bool' } }
+
+##
+# @InputBtnEvent
+#
+# Pointer button input event.
+#
+# @button: Which button this event is for.
+# @down: True for key-down and false for key-up events.
+#
+# Since: 2.0
+##
+{ 'type' : 'InputBtnEvent',
+ 'data' : { 'button' : 'InputButton',
+ 'down' : 'bool' } }
+
+##
+# @InputMoveEvent
+#
+# Pointer motion input event.
+#
+# @axis: Which axis is referenced by @value.
+# @value: Pointer position. For absolute coordinates the
+# valid range is 0 -> 0x7ffff
+#
+# Since: 2.0
+##
+{ 'type' : 'InputMoveEvent',
+ 'data' : { 'axis' : 'InputAxis',
+ 'value' : 'int' } }
+
+##
+# @InputEvent
+#
+# Input event union.
+#
+# Since: 2.0
+##
+{ 'union' : 'InputEvent',
+ 'data' : { 'key' : 'InputKeyEvent',
+ 'btn' : 'InputBtnEvent',
+ 'rel' : 'InputMoveEvent',
+ 'abs' : 'InputMoveEvent' } }
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index 96ed85899d..5d830a2b56 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -124,7 +124,9 @@ opts_start_struct(Visitor *v, void **obj, const char *kind,
OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);
const QemuOpt *opt;
- *obj = g_malloc0(size > 0 ? size : 1);
+ if (obj) {
+ *obj = g_malloc0(size > 0 ? size : 1);
+ }
if (ov->depth++ > 0) {
return;
}
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
index dc53545fa5..d0ea118fe3 100644
--- a/qapi/qapi-dealloc-visitor.c
+++ b/qapi/qapi-dealloc-visitor.c
@@ -131,9 +131,7 @@ static void qapi_dealloc_end_list(Visitor *v, Error **errp)
static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name,
Error **errp)
{
- if (obj) {
- g_free(*obj);
- }
+ g_free(*obj);
}
static void qapi_dealloc_type_int(Visitor *v, int64_t *obj, const char *name,
diff --git a/qemu-file.c b/qemu-file.c
index f074af15c3..e5ec798e0b 100644
--- a/qemu-file.c
+++ b/qemu-file.c
@@ -105,7 +105,7 @@ static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos,
res = fwrite(buf, 1, size, s->stdio_file);
if (res != size) {
- return -EIO; /* fake errno value */
+ return -errno;
}
return res;
}
diff --git a/qemu-img.c b/qemu-img.c
index 78fc86826c..2e40cc1e69 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -32,12 +32,6 @@
#include "block/block_int.h"
#include "block/qapi.h"
#include <getopt.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
typedef struct img_cmd_t {
const char *name;
@@ -1168,9 +1162,6 @@ static int img_convert(int argc, char **argv)
Error *local_err = NULL;
QemuOpts *sn_opts = NULL;
- /* Initialize before goto out */
- qemu_progress_init(progress, 1.0);
-
fmt = NULL;
out_fmt = "raw";
cache = "unsafe";
@@ -1203,17 +1194,17 @@ static int img_convert(int argc, char **argv)
error_report("option -e is deprecated, please use \'-o "
"encryption\' instead!");
ret = -1;
- goto out;
+ goto fail_getopt;
case '6':
error_report("option -6 is deprecated, please use \'-o "
"compat6\' instead!");
ret = -1;
- goto out;
+ goto fail_getopt;
case 'o':
if (!is_valid_option_list(optarg)) {
error_report("Invalid option list: %s", optarg);
ret = -1;
- goto out;
+ goto fail_getopt;
}
if (!options) {
options = g_strdup(optarg);
@@ -1233,7 +1224,7 @@ static int img_convert(int argc, char **argv)
error_report("Failed in parsing snapshot param '%s'",
optarg);
ret = -1;
- goto out;
+ goto fail_getopt;
}
} else {
snapshot_name = optarg;
@@ -1247,7 +1238,7 @@ static int img_convert(int argc, char **argv)
if (sval < 0 || *end) {
error_report("Invalid minimum zero buffer size for sparse output specified");
ret = -1;
- goto out;
+ goto fail_getopt;
}
min_sparse = sval / BDRV_SECTOR_SIZE;
@@ -1268,9 +1259,12 @@ static int img_convert(int argc, char **argv)
}
}
+ /* Initialize before goto out */
if (quiet) {
progress = 0;
}
+ qemu_progress_init(progress, 1.0);
+
bs_n = argc - optind - 1;
out_filename = bs_n >= 1 ? argv[argc - 1] : NULL;
@@ -1673,7 +1667,6 @@ out:
free_option_parameters(create_options);
free_option_parameters(param);
qemu_vfree(buf);
- g_free(options);
if (sn_opts) {
qemu_opts_del(sn_opts);
}
@@ -1688,6 +1681,9 @@ out:
}
g_free(bs);
}
+fail_getopt:
+ g_free(options);
+
if (ret) {
return 1;
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 56e5fdf1e0..068da2df09 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -328,9 +328,11 @@ possible drivers and properties, use @code{-device help} and
ETEXI
DEF("name", HAS_ARG, QEMU_OPTION_name,
- "-name string1[,process=string2]\n"
+ "-name string1[,process=string2][,debug-threads=on|off]\n"
" set the name of the guest\n"
- " string1 sets the window title and string2 the process name (on Linux)\n",
+ " string1 sets the window title and string2 the process name (on Linux)\n"
+ " When debug-threads is enabled, individual threads are given a separate name (on Linux)\n"
+ " NOTE: The thread names are for debugging and not a stable API.\n",
QEMU_ARCH_ALL)
STEXI
@item -name @var{name}
@@ -339,6 +341,7 @@ Sets the @var{name} of the guest.
This name will be displayed in the SDL window caption.
The @var{name} will also be used for the VNC server.
Also optionally set the top visible process name in Linux.
+Naming of individual threads can also be enabled on Linux to aid debugging.
ETEXI
DEF("uuid", HAS_ARG, QEMU_OPTION_uuid,
diff --git a/qga/main.c b/qga/main.c
index cfca291b43..d838c3e32a 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -35,7 +35,6 @@
#ifdef _WIN32
#include "qga/service-win32.h"
#include "qga/vss-win32.h"
-#include <windows.h>
#endif
#ifdef __linux__
#include <linux/fs.h>
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 8a0e8320c6..d982cd62b9 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -791,8 +791,8 @@ EQMP
{
.name = "dump-guest-memory",
- .args_type = "paging:b,protocol:s,begin:i?,end:i?",
- .params = "-p protocol [begin] [length]",
+ .args_type = "paging:b,protocol:s,begin:i?,end:i?,format:s?",
+ .params = "-p protocol [begin] [length] [format]",
.help = "dump guest memory to file",
.user_print = monitor_user_noop,
.mhandler.cmd_new = qmp_marshal_input_dump_guest_memory,
@@ -813,6 +813,9 @@ Arguments:
with length together (json-int)
- "length": the memory size, in bytes. It's optional, and should be specified
with begin together (json-int)
+- "format": the format of guest memory dump. It's optional, and can be
+ elf|kdump-zlib|kdump-lzo|kdump-snappy, but non-elf formats will
+ conflict with paging and filter, ie. begin and length (json-string)
Example:
@@ -826,6 +829,26 @@ Notes:
EQMP
{
+ .name = "query-dump-guest-memory-capability",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_dump_guest_memory_capability,
+ },
+
+SQMP
+query-dump-guest-memory-capability
+----------
+
+Show available formats for 'dump-guest-memory'
+
+Example:
+
+-> { "execute": "query-dump-guest-memory-capability" }
+<- { "return": { "formats":
+ ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] }
+
+EQMP
+
+ {
.name = "netdev_add",
.args_type = "netdev:O",
.mhandler.cmd_new = qmp_netdev_add,
diff --git a/qmp.c b/qmp.c
index d0d98e777b..f556a04d19 100644
--- a/qmp.c
+++ b/qmp.c
@@ -556,8 +556,8 @@ void object_add(const char *type, const char *id, const QDict *qdict,
}
if (!object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
- error_setg(&local_err, "object '%s' isn't supported by object-add",
- id);
+ error_setg(&local_err, "object type '%s' isn't supported by object-add",
+ type);
goto out;
}
diff --git a/qtest.c b/qtest.c
index ae941d6551..0ac9f429f5 100644
--- a/qtest.c
+++ b/qtest.c
@@ -500,7 +500,7 @@ static void qtest_event(void *opaque, int event)
}
}
-int qtest_init_accel(void)
+int qtest_init_accel(QEMUMachine *machine)
{
configure_icount("0");
diff --git a/roms/openbios b/roms/openbios
-Subproject 888126272f92294b0da45158393f1b862742cf6
+Subproject 1ac3fb92c109f5545d373a0576b87750c53cce1
diff --git a/savevm.c b/savevm.c
index 7329fc58de..d094fbb854 100644
--- a/savevm.c
+++ b/savevm.c
@@ -527,13 +527,13 @@ int qemu_savevm_state_iterate(QEMUFile *f)
if (qemu_file_rate_limit(f)) {
return 0;
}
- trace_savevm_section_start();
+ trace_savevm_section_start(se->idstr, se->section_id);
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_PART);
qemu_put_be32(f, se->section_id);
ret = se->ops->save_live_iterate(f, se->opaque);
- trace_savevm_section_end(se->section_id);
+ trace_savevm_section_end(se->idstr, se->section_id);
if (ret < 0) {
qemu_file_set_error(f, ret);
@@ -565,13 +565,13 @@ void qemu_savevm_state_complete(QEMUFile *f)
continue;
}
}
- trace_savevm_section_start();
+ trace_savevm_section_start(se->idstr, se->section_id);
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
ret = se->ops->save_live_complete(f, se->opaque);
- trace_savevm_section_end(se->section_id);
+ trace_savevm_section_end(se->idstr, se->section_id);
if (ret < 0) {
qemu_file_set_error(f, ret);
return;
@@ -584,7 +584,7 @@ void qemu_savevm_state_complete(QEMUFile *f)
if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
continue;
}
- trace_savevm_section_start();
+ trace_savevm_section_start(se->idstr, se->section_id);
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_FULL);
qemu_put_be32(f, se->section_id);
@@ -598,7 +598,7 @@ void qemu_savevm_state_complete(QEMUFile *f)
qemu_put_be32(f, se->version_id);
vmstate_save(f, se);
- trace_savevm_section_end(se->section_id);
+ trace_savevm_section_end(se->idstr, se->section_id);
}
qemu_put_byte(f, QEMU_VM_EOF);
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index b12b6964ef..9734ab0a53 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -7,8 +7,8 @@
# Anthony Liguori <aliguori@us.ibm.com>
# Michael Roth <mdroth@linux.vnet.ibm.com>
#
-# This work is licensed under the terms of the GNU GPLv2.
-# See the COPYING.LIB file in the top-level directory.
+# This work is licensed under the terms of the GNU GPL, version 2.
+# See the COPYING file in the top-level directory.
from ordereddict import OrderedDict
from qapi import *
@@ -23,13 +23,6 @@ def type_visitor(name):
else:
return 'visit_type_%s' % name
-def generate_decl_enum(name, members, genlist=True):
- return mcgen('''
-
-void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
-''',
- visitor=type_visitor(name))
-
def generate_command_decl(name, args, ret_type):
arglist=""
for argname, argtype, optional, structured in parse_args(args):
@@ -76,19 +69,6 @@ def gen_marshal_output_call(name, ret_type):
return ""
return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name)
-def gen_visitor_output_containers_decl(ret_type):
- ret = ""
- push_indent()
- if ret_type:
- ret += mcgen('''
-QmpOutputVisitor *mo;
-QapiDeallocVisitor *md;
-Visitor *v;
-''')
- pop_indent()
-
- return ret
-
def gen_visitor_input_containers_decl(args):
ret = ""
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 4a1652b56f..2c6e0dcd5c 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -6,8 +6,8 @@
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
#
-# This work is licensed under the terms of the GNU GPLv2.
-# See the COPYING.LIB file in the top-level directory.
+# This work is licensed under the terms of the GNU GPL, version 2.
+# See the COPYING file in the top-level directory.
from ordereddict import OrderedDict
from qapi import *
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 65f1a54ee7..c6de9aeed4 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -7,8 +7,8 @@
# Anthony Liguori <aliguori@us.ibm.com>
# Michael Roth <mdroth@linux.vnet.ibm.com>
#
-# This work is licensed under the terms of the GNU GPLv2.
-# See the COPYING.LIB file in the top-level directory.
+# This work is licensed under the terms of the GNU GPL, version 2.
+# See the COPYING file in the top-level directory.
from ordereddict import OrderedDict
from qapi import *
@@ -47,9 +47,9 @@ static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error *
if base:
ret += mcgen('''
-visit_start_implicit_struct(m, obj ? (void**) &(*obj)->%(c_name)s : NULL, sizeof(%(type)s), &err);
+visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(type)s), &err);
if (!err) {
- visit_type_%(type)s_fields(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, &err);
+ visit_type_%(type)s_fields(m, &(*obj)->%(c_prefix)s%(c_name)s, &err);
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
@@ -61,8 +61,8 @@ if (!err) {
for argname, argentry, optional, structured in parse_args(members):
if optional:
ret += mcgen('''
-visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
-if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
+visit_start_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err);
+if ((*obj)->%(prefix)shas_%(c_name)s) {
''',
c_prefix=c_var(field_prefix), prefix=field_prefix,
c_name=c_var(argname), name=argname)
@@ -72,7 +72,7 @@ if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
ret += generate_visit_struct_body(full_name, argname, argentry)
else:
ret += mcgen('''
-visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
+visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
''',
c_prefix=c_var(field_prefix), prefix=field_prefix,
type=type_name(argentry), c_name=c_var(argname),
@@ -121,7 +121,7 @@ visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
ret += mcgen('''
if (!err) {
- if (!obj || *obj) {
+ if (*obj) {
visit_type_%(name)s_fields(m, obj, &err);
error_propagate(errp, err);
err = NULL;
@@ -273,7 +273,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
if (!error_is_set(errp)) {
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
if (!err) {
- if (obj && *obj) {
+ if (*obj) {
''',
name=name)
@@ -494,10 +494,8 @@ fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
# have the functions defined, so we use -b option to provide control
# over these cases
if do_builtins:
- fdef.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DEF"))
for typename in builtin_types:
fdef.write(generate_visit_list(typename, None))
- fdef.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DEF"))
for expr in exprs:
if expr.has_key('type'):
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 9b3de4c7c3..f3c2a2037a 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -8,8 +8,8 @@
# Anthony Liguori <aliguori@us.ibm.com>
# Markus Armbruster <armbru@redhat.com>
#
-# This work is licensed under the terms of the GNU GPLv2.
-# See the COPYING.LIB file in the top-level directory.
+# This work is licensed under the terms of the GNU GPL, version 2.
+# See the COPYING file in the top-level directory.
from ordereddict import OrderedDict
import sys
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index d374b357aa..e0e848bc30 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -112,13 +112,29 @@ class QMPShell(qmp.QEMUMonitorProtocol):
value = json.loads(opt[1])
else:
value = opt[1]
- qmpcmd['arguments'][opt[0]] = value
+ optpath = opt[0].split('.')
+ parent = qmpcmd['arguments']
+ curpath = []
+ for p in optpath[:-1]:
+ curpath.append(p)
+ d = parent.get(p, {})
+ if type(d) is not dict:
+ raise QMPShellError('Cannot use "%s" as both leaf and non-leaf key' % '.'.join(curpath))
+ parent[p] = d
+ parent = d
+ if optpath[-1] in parent:
+ if type(parent[optpath[-1]]) is dict:
+ raise QMPShellError('Cannot use "%s" as both leaf and non-leaf key' % '.'.join(curpath))
+ else:
+ raise QMPShellError('Cannot set "%s" multiple times' % opt[0])
+ parent[optpath[-1]] = value
return qmpcmd
def _execute_cmd(self, cmdline):
try:
qmpcmd = self.__build_cmd(cmdline)
- except:
+ except Exception, e:
+ print 'Error while parsing command line: %s' % e
print 'command format: <command-name> ',
print '[arg-name1=arg1] ... [arg-nameN=argN]'
return True
diff --git a/scripts/qmp/qmp.py b/scripts/qmp/qmp.py
index 5c9717594f..20b6ec795e 100644
--- a/scripts/qmp/qmp.py
+++ b/scripts/qmp/qmp.py
@@ -171,7 +171,12 @@ class QEMUMonitorProtocol:
pass
self.__sock.setblocking(1)
if not self.__events and wait:
- self.__json_read(only_event=True)
+ ret = self.__json_read(only_event=True)
+ if ret == None:
+ # We are in blocking mode, if don't get anything, something
+ # went wrong
+ raise QMPConnectError("Error while reading from socket")
+
return self.__events
def clear_events(self):
diff --git a/stubs/gdbstub.c b/stubs/gdbstub.c
index c1dbfe7fb7..f6a4553a31 100644
--- a/stubs/gdbstub.c
+++ b/stubs/gdbstub.c
@@ -1,4 +1,6 @@
-#include "qemu-common.h"
+#include "stdbool.h" /* bool (in exec/gdbstub.h) */
+#include "stddef.h" /* NULL */
+#include "exec/gdbstub.h" /* xml_builtin */
const char *const xml_builtin[][2] = {
{ NULL, NULL }
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 49fef3fcbe..0a7edfe6cb 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -222,6 +222,10 @@ typedef struct CPUARMState {
uint64_t dbgbcr[16]; /* breakpoint control registers */
uint64_t dbgwvr[16]; /* watchpoint value registers */
uint64_t dbgwcr[16]; /* watchpoint control registers */
+ /* If the counter is enabled, this stores the last time the counter
+ * was reset. Otherwise it stores the counter value
+ */
+ uint32_t c15_ccnt;
} cp15;
struct {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 90f85f1899..f65cbac1ee 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -13,6 +13,11 @@ static inline int get_phys_addr(CPUARMState *env, uint32_t address,
int access_type, int is_user,
hwaddr *phys_ptr, int *prot,
target_ulong *page_size);
+
+/* Definitions for the PMCCNTR and PMCR registers */
+#define PMCRD 0x8
+#define PMCRC 0x4
+#define PMCRE 0x1
#endif
static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
@@ -478,13 +483,84 @@ static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri)
return CP_ACCESS_OK;
}
+#ifndef CONFIG_USER_ONLY
static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
+ /* Don't computer the number of ticks in user mode */
+ uint32_t temp_ticks;
+
+ temp_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
+ get_ticks_per_sec() / 1000000;
+
+ if (env->cp15.c9_pmcr & PMCRE) {
+ /* If the counter is enabled */
+ if (env->cp15.c9_pmcr & PMCRD) {
+ /* Increment once every 64 processor clock cycles */
+ env->cp15.c15_ccnt = (temp_ticks/64) - env->cp15.c15_ccnt;
+ } else {
+ env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt;
+ }
+ }
+
+ if (value & PMCRC) {
+ /* The counter has been reset */
+ env->cp15.c15_ccnt = 0;
+ }
+
/* only the DP, X, D and E bits are writable */
env->cp15.c9_pmcr &= ~0x39;
env->cp15.c9_pmcr |= (value & 0x39);
+
+ if (env->cp15.c9_pmcr & PMCRE) {
+ if (env->cp15.c9_pmcr & PMCRD) {
+ /* Increment once every 64 processor clock cycles */
+ temp_ticks /= 64;
+ }
+ env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt;
+ }
+}
+
+static uint64_t pmccntr_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ uint32_t total_ticks;
+
+ if (!(env->cp15.c9_pmcr & PMCRE)) {
+ /* Counter is disabled, do not change value */
+ return env->cp15.c15_ccnt;
+ }
+
+ total_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
+ get_ticks_per_sec() / 1000000;
+
+ if (env->cp15.c9_pmcr & PMCRD) {
+ /* Increment once every 64 processor clock cycles */
+ total_ticks /= 64;
+ }
+ return total_ticks - env->cp15.c15_ccnt;
+}
+
+static void pmccntr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint32_t total_ticks;
+
+ if (!(env->cp15.c9_pmcr & PMCRE)) {
+ /* Counter is disabled, set the absolute value */
+ env->cp15.c15_ccnt = value;
+ return;
+ }
+
+ total_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
+ get_ticks_per_sec() / 1000000;
+
+ if (env->cp15.c9_pmcr & PMCRD) {
+ /* Increment once every 64 processor clock cycles */
+ total_ticks /= 64;
+ }
+ env->cp15.c15_ccnt = total_ticks - value;
}
+#endif
static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
@@ -604,10 +680,12 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
{ .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5,
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0,
.accessfn = pmreg_access },
- /* Unimplemented, RAZ/WI. */
+#ifndef CONFIG_USER_ONLY
{ .name = "PMCCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 0,
- .access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0,
+ .access = PL0_RW, .resetvalue = 0, .type = ARM_CP_IO,
+ .readfn = pmccntr_read, .writefn = pmccntr_write,
.accessfn = pmreg_access },
+#endif
{ .name = "PMXEVTYPER", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 1,
.access = PL0_RW,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmxevtyper),
@@ -1873,8 +1951,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
}
if (arm_feature(env, ARM_FEATURE_V7)) {
/* v7 performance monitor control register: same implementor
- * field as main ID register, and we implement no event counters.
+ * field as main ID register, and we implement only the cycle
+ * count register.
*/
+#ifndef CONFIG_USER_ONLY
ARMCPRegInfo pmcr = {
.name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0,
.access = PL0_RW, .resetvalue = cpu->midr & 0xff000000,
@@ -1882,12 +1962,13 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.accessfn = pmreg_access, .writefn = pmcr_write,
.raw_writefn = raw_write,
};
+ define_one_arm_cp_reg(cpu, &pmcr);
+#endif
ARMCPRegInfo clidr = {
.name = "CLIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->clidr
};
- define_one_arm_cp_reg(cpu, &pmcr);
define_one_arm_cp_reg(cpu, &clidr);
define_arm_cp_regs(cpu, v7_cp_reginfo);
} else {
@@ -2478,7 +2559,7 @@ uint32_t cpsr_read(CPUARMState *env)
(env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
| (env->thumb << 5) | ((env->condexec_bits & 3) << 25)
| ((env->condexec_bits & 0xfc) << 8)
- | (env->GE << 16) | env->daif;
+ | (env->GE << 16) | (env->daif & CPSR_AIF);
}
void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
diff --git a/target-arm/helper.h b/target-arm/helper.h
index 276f3a9149..8923f8ae71 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -50,6 +50,7 @@ DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE,
i32, i32, i32, i32)
DEF_HELPER_2(exception, void, env, i32)
DEF_HELPER_1(wfi, void, env)
+DEF_HELPER_1(wfe, void, env)
DEF_HELPER_3(cpsr_write, void, env, i32, i32)
DEF_HELPER_1(cpsr_read, i32, env)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 7d06d2f9a5..5851e041a0 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -225,6 +225,15 @@ void HELPER(wfi)(CPUARMState *env)
cpu_loop_exit(env);
}
+void HELPER(wfe)(CPUARMState *env)
+{
+ /* Don't actually halt the CPU, just yield back to top
+ * level loop
+ */
+ env->exception_index = EXCP_YIELD;
+ cpu_loop_exit(env);
+}
+
void HELPER(exception)(CPUARMState *env, uint32_t excp)
{
env->exception_index = excp;
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 08ac6591b6..37e05e81f7 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -210,7 +210,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
if (use_goto_tb(s, n, dest)) {
tcg_gen_goto_tb(n);
gen_a64_set_pc_im(dest);
- tcg_gen_exit_tb((tcg_target_long)tb + n);
+ tcg_gen_exit_tb((intptr_t)tb + n);
s->is_jmp = DISAS_TB_JUMP;
} else {
gen_a64_set_pc_im(dest);
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 253d2a13eb..df259debcc 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -3939,6 +3939,9 @@ static void gen_nop_hint(DisasContext *s, int val)
s->is_jmp = DISAS_WFI;
break;
case 2: /* wfe */
+ gen_set_pc_im(s, s->pc);
+ s->is_jmp = DISAS_WFE;
+ break;
case 4: /* sev */
case 5: /* sevl */
/* TODO: Implement SEV, SEVL and WFE. May help SMP performance. */
@@ -10857,6 +10860,9 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
case DISAS_WFI:
gen_helper_wfi(cpu_env);
break;
+ case DISAS_WFE:
+ gen_helper_wfe(cpu_env);
+ break;
case DISAS_SWI:
gen_exception(EXCP_SWI);
break;
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 67da6996c9..2f491f9ff6 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -44,6 +44,8 @@ extern TCGv_ptr cpu_env;
* emitting unreachable code at the end of the TB in the A64 decoder
*/
#define DISAS_EXC 6
+/* WFE */
+#define DISAS_WFE 7
#ifdef TARGET_AARCH64
void a64_translate_init(void);
diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c
index ee04092b4e..05dd12b5a7 100644
--- a/target-i386/cc_helper.c
+++ b/target-i386/cc_helper.c
@@ -103,7 +103,7 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
case CC_OP_EFLAGS:
return src1;
case CC_OP_CLR:
- return CC_Z;
+ return CC_Z | CC_P;
case CC_OP_MULB:
return compute_all_mulb(dst, src1);
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 1b94f0ffb7..0014acca7b 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -38,8 +38,10 @@
#ifdef TARGET_X86_64
#define ELF_MACHINE EM_X86_64
+#define ELF_MACHINE_UNAME "x86_64"
#else
#define ELF_MACHINE EM_386
+#define ELF_MACHINE_UNAME "i686"
#endif
#define CPUArchState struct CPUX86State
@@ -1259,6 +1261,9 @@ static inline void cpu_load_efer(CPUX86State *env, uint64_t val)
}
}
+/* fpu_helper.c */
+void cpu_set_mxcsr(CPUX86State *env, uint32_t val);
+
/* svm_helper.c */
void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
uint64_t param);
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index c0427fec7a..de7ba76a49 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -1179,7 +1179,7 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64)
if (env->cr[4] & CR4_OSFXSR_MASK) {
/* XXX: finish it */
- env->mxcsr = cpu_ldl_data(env, ptr + 0x18);
+ cpu_set_mxcsr(env, cpu_ldl_data(env, ptr + 0x18));
/* cpu_ldl_data(env, ptr + 0x1c); */
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
@@ -1229,12 +1229,14 @@ floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
#define SSE_RC_CHOP 0x6000
#define SSE_FZ 0x8000
-static void update_sse_status(CPUX86State *env)
+void cpu_set_mxcsr(CPUX86State *env, uint32_t mxcsr)
{
int rnd_type;
+ env->mxcsr = mxcsr;
+
/* set rounding mode */
- switch (env->mxcsr & SSE_RC_MASK) {
+ switch (mxcsr & SSE_RC_MASK) {
default:
case SSE_RC_NEAR:
rnd_type = float_round_nearest_even;
@@ -1252,16 +1254,15 @@ static void update_sse_status(CPUX86State *env)
set_float_rounding_mode(rnd_type, &env->sse_status);
/* set denormals are zero */
- set_flush_inputs_to_zero((env->mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status);
+ set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status);
/* set flush to zero */
- set_flush_to_zero((env->mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
+ set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
}
void helper_ldmxcsr(CPUX86State *env, uint32_t val)
{
- env->mxcsr = val;
- update_sse_status(env);
+ cpu_set_mxcsr(env, val);
}
void helper_enter_mmx(CPUX86State *env)
diff --git a/target-i386/gdbstub.c b/target-i386/gdbstub.c
index 15bebeff89..d34e5355f7 100644
--- a/target-i386/gdbstub.c
+++ b/target-i386/gdbstub.c
@@ -222,7 +222,7 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 4;
case IDX_MXCSR_REG:
- env->mxcsr = ldl_p(mem_buf);
+ cpu_set_mxcsr(env, ldl_p(mem_buf));
return 4;
}
}
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 5dd2450798..707ebd5ca0 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -748,7 +748,7 @@ static void gen_compute_eflags(DisasContext *s)
return;
}
if (s->cc_op == CC_OP_CLR) {
- tcg_gen_movi_tl(cpu_cc_src, CC_Z);
+ tcg_gen_movi_tl(cpu_cc_src, CC_Z | CC_P);
set_cc_op(s, CC_OP_EFLAGS);
return;
}
@@ -4284,22 +4284,48 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
if (is_xmm) {
op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
if (mod != 3) {
+ int sz = 4;
+
gen_lea_modrm(env, s, modrm);
op2_offset = offsetof(CPUX86State,xmm_t0);
- if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) ||
- b == 0xc2)) {
- /* specific case for SSE single instructions */
+
+ switch (b) {
+ case 0x50 ... 0x5a:
+ case 0x5c ... 0x5f:
+ case 0xc2:
+ /* Most sse scalar operations. */
if (b1 == 2) {
- /* 32 bit access */
- gen_op_ld_v(s, MO_32, cpu_T[0], cpu_A0);
- tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
+ sz = 2;
+ } else if (b1 == 3) {
+ sz = 3;
+ }
+ break;
+
+ case 0x2e: /* ucomis[sd] */
+ case 0x2f: /* comis[sd] */
+ if (b1 == 0) {
+ sz = 2;
} else {
- /* 64 bit access */
- gen_ldq_env_A0(s, offsetof(CPUX86State,
- xmm_t0.XMM_D(0)));
+ sz = 3;
}
- } else {
+ break;
+ }
+
+ switch (sz) {
+ case 2:
+ /* 32 bit access */
+ gen_op_ld_v(s, MO_32, cpu_T[0], cpu_A0);
+ tcg_gen_st32_tl(cpu_T[0], cpu_env,
+ offsetof(CPUX86State,xmm_t0.XMM_L(0)));
+ break;
+ case 3:
+ /* 64 bit access */
+ gen_ldq_env_A0(s, offsetof(CPUX86State, xmm_t0.XMM_D(0)));
+ break;
+ default:
+ /* 128 bit access */
gen_ldo_env_A0(s, op2_offset);
+ break;
}
} else {
rm = (modrm & 7) | REX_B(s);
diff --git a/target-ppc/STATUS b/target-ppc/STATUS
index c8e9018bfc..a4d48a7ca2 100644
--- a/target-ppc/STATUS
+++ b/target-ppc/STATUS
@@ -377,15 +377,6 @@ MMU OK
EXCP KO partially implemented
Remarks: Should be able to boot but there is no hw platform currently emulated.
-PowerPC 970GX:
-INSN KO Altivec missing and more
-SPR KO
-MSR ?
-IRQ OK
-MMU OK
-EXCP KO partially implemented
-Remarks: Should be able to boot but there is no hw platform currently emulated.
-
PowerPC Cell:
INSN KO Altivec missing and more
SPR KO
diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
index 7c9466fc07..f6c9b3ab01 100644
--- a/target-ppc/cpu-models.c
+++ b/target-ppc/cpu-models.c
@@ -1156,8 +1156,6 @@
"PowerPC 970FX v3.0 (G5)")
POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX,
"PowerPC 970FX v3.1 (G5)")
- POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX,
- "PowerPC 970GX (G5)")
POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP,
"PowerPC 970MP v1.0")
POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP,
diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
index 49ba4a4522..644a126459 100644
--- a/target-ppc/cpu-models.h
+++ b/target-ppc/cpu-models.h
@@ -570,7 +570,6 @@ enum {
CPU_POWERPC_970FX_v21 = 0x003C0201,
CPU_POWERPC_970FX_v30 = 0x003C0300,
CPU_POWERPC_970FX_v31 = 0x003C0301,
- CPU_POWERPC_970GX = 0x00450000,
CPU_POWERPC_970MP_v10 = 0x00440100,
CPU_POWERPC_970MP_v11 = 0x00440101,
#define CPU_POWERPC_CELL CPU_POWERPC_CELL_v32
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 72b22329b0..b17c024543 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -79,6 +79,7 @@ typedef struct PowerPCCPUClass {
/**
* PowerPCCPU:
* @env: #CPUPPCState
+ * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
*
* A PowerPC CPU.
*/
@@ -88,6 +89,7 @@ typedef struct PowerPCCPU {
/*< public >*/
CPUPPCState env;
+ int cpu_dt_id;
} PowerPCCPU;
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index bb847676a5..afab267485 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -352,6 +352,10 @@ union ppc_avr_t {
int16_t s16[8];
int32_t s32[4];
uint64_t u64[2];
+ int64_t s64[2];
+#ifdef CONFIG_INT128
+ __uint128_t u128;
+#endif
};
#if !defined(CONFIG_USER_ONLY)
@@ -926,6 +930,7 @@ struct CPUPPCState {
target_ulong reserve_addr;
/* Reservation value */
target_ulong reserve_val;
+ target_ulong reserve_val2;
/* Reservation store address */
target_ulong reserve_ea;
/* Reserved store source register and size */
@@ -961,6 +966,7 @@ struct CPUPPCState {
#endif
/* segment registers */
hwaddr htab_base;
+ /* mask used to normalize hash value to PTEG index */
hwaddr htab_mask;
target_ulong sr[32];
/* externally stored hash table */
@@ -1250,7 +1256,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_MPC_EIE (0x050)
#define SPR_MPC_EID (0x051)
#define SPR_MPC_NRI (0x052)
-#define SPR_CTRL (0x088)
+#define SPR_UCTRL (0x088)
#define SPR_MPC_CMPA (0x090)
#define SPR_MPC_CMPB (0x091)
#define SPR_MPC_CMPC (0x092)
@@ -1259,7 +1265,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_MPC_DER (0x095)
#define SPR_MPC_COUNTA (0x096)
#define SPR_MPC_COUNTB (0x097)
-#define SPR_UCTRL (0x098)
+#define SPR_CTRL (0x098)
#define SPR_MPC_CMPE (0x098)
#define SPR_MPC_CMPF (0x099)
#define SPR_MPC_CMPG (0x09A)
@@ -1322,12 +1328,12 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_BOOKE_IAC3 (0x13A)
#define SPR_HSRR1 (0x13B)
#define SPR_BOOKE_IAC4 (0x13B)
-#define SPR_LPCR (0x13C)
#define SPR_BOOKE_DAC1 (0x13C)
#define SPR_LPIDR (0x13D)
#define SPR_DABR2 (0x13D)
#define SPR_BOOKE_DAC2 (0x13D)
#define SPR_BOOKE_DVC1 (0x13E)
+#define SPR_LPCR (0x13E)
#define SPR_BOOKE_DVC2 (0x13F)
#define SPR_BOOKE_TSR (0x150)
#define SPR_BOOKE_TCR (0x154)
@@ -1508,6 +1514,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_RCPU_L2U_RA2 (0x32A)
#define SPR_MPC_MD_DBRAM1 (0x32A)
#define SPR_RCPU_L2U_RA3 (0x32B)
+#define SPR_TAR (0x32F)
#define SPR_440_INV0 (0x370)
#define SPR_440_INV1 (0x371)
#define SPR_440_INV2 (0x372)
@@ -1875,9 +1882,31 @@ enum {
PPC2_DBRX = 0x0000000000000010ULL,
/* Book I 2.05 PowerPC specification */
PPC2_ISA205 = 0x0000000000000020ULL,
+ /* VSX additions in ISA 2.07 */
+ PPC2_VSX207 = 0x0000000000000040ULL,
+ /* ISA 2.06B bpermd */
+ PPC2_PERM_ISA206 = 0x0000000000000080ULL,
+ /* ISA 2.06B divide extended variants */
+ PPC2_DIVE_ISA206 = 0x0000000000000100ULL,
+ /* ISA 2.06B larx/stcx. instructions */
+ PPC2_ATOMIC_ISA206 = 0x0000000000000200ULL,
+ /* ISA 2.06B floating point integer conversion */
+ PPC2_FP_CVT_ISA206 = 0x0000000000000400ULL,
+ /* ISA 2.06B floating point test instructions */
+ PPC2_FP_TST_ISA206 = 0x0000000000000800ULL,
+ /* ISA 2.07 bctar instruction */
+ PPC2_BCTAR_ISA207 = 0x0000000000001000ULL,
+ /* ISA 2.07 load/store quadword */
+ PPC2_LSQ_ISA207 = 0x0000000000002000ULL,
+ /* ISA 2.07 Altivec */
+ PPC2_ALTIVEC_207 = 0x0000000000004000ULL,
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
- PPC2_ISA205)
+ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
+ PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
+ PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
+ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
+ PPC2_ALTIVEC_207)
};
/*****************************************************************************/
@@ -2154,4 +2183,22 @@ static inline bool cpu_has_work(CPUState *cpu)
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
+/**
+ * ppc_get_vcpu_dt_id:
+ * @cs: a PowerPCCPU struct.
+ *
+ * Returns a device-tree ID for a CPU.
+ */
+int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
+
+/**
+ * ppc_get_vcpu_by_dt_id:
+ * @cpu_dt_id: a device tree id
+ *
+ * Searches for a CPU by @cpu_dt_id.
+ *
+ * Returns: a PowerPCCPU struct
+ */
+PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
+
#endif /* !defined (__CPU_PPC_H__) */
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index 4f6021835f..e7f329566d 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -50,6 +50,16 @@ static inline int isden(float64 d)
return ((u.ll >> 52) & 0x7FF) == 0;
}
+static inline int ppc_float32_get_unbiased_exp(float32 f)
+{
+ return ((f >> 23) & 0xFF) - 127;
+}
+
+static inline int ppc_float64_get_unbiased_exp(float64 f)
+{
+ return ((f >> 52) & 0x7FF) - 1023;
+}
+
uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf)
{
CPU_DoubleU farg;
@@ -106,7 +116,8 @@ uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf)
}
/* Floating-point invalid operations exception */
-static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
+static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
+ int set_fpcc)
{
uint64_t ret = 0;
int ve;
@@ -138,8 +149,10 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
case POWERPC_EXCP_FP_VXVC:
/* Ordered comparison of NaN */
env->fpscr |= 1 << FPSCR_VXVC;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ if (set_fpcc) {
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
/* We must update the target FPR before raising the exception */
if (ve != 0) {
env->exception_index = POWERPC_EXCP_PROGRAM;
@@ -158,8 +171,10 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
if (ve == 0) {
/* Set the result to quiet NaN */
ret = 0x7FF8000000000000ULL;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ if (set_fpcc) {
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
}
break;
case POWERPC_EXCP_FP_VXCVI:
@@ -169,8 +184,10 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
if (ve == 0) {
/* Set the result to quiet NaN */
ret = 0x7FF8000000000000ULL;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ if (set_fpcc) {
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
}
break;
}
@@ -505,12 +522,12 @@ uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN addition */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
}
@@ -529,12 +546,12 @@ uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN subtraction */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
}
@@ -553,12 +570,12 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN multiplication */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
}
@@ -577,15 +594,15 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) &&
float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
/* Division of zero by zero */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN division */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
}
@@ -593,107 +610,63 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
return farg1.ll;
}
-/* fctiw - fctiw. */
-uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int32(farg.d, &env->fp_status);
- /* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750
- */
- farg.ll |= 0xFFF80000ULL << 32;
- }
- return farg.ll;
-}
-
-/* fctiwz - fctiwz. */
-uint64_t helper_fctiwz(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
- /* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750
- */
- farg.ll |= 0xFFF80000ULL << 32;
- }
- return farg.ll;
-}
+#define FPU_FCTI(op, cvt, nanval) \
+uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
+{ \
+ CPU_DoubleU farg; \
+ \
+ farg.ll = arg; \
+ farg.ll = float64_to_##cvt(farg.d, &env->fp_status); \
+ \
+ if (unlikely(env->fp_status.float_exception_flags)) { \
+ if (float64_is_any_nan(arg)) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \
+ if (float64_is_signaling_nan(arg)) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
+ } \
+ farg.ll = nanval; \
+ } else if (env->fp_status.float_exception_flags & \
+ float_flag_invalid) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \
+ } \
+ helper_float_check_status(env); \
+ } \
+ return farg.ll; \
+ }
+
+FPU_FCTI(fctiw, int32, 0x80000000U)
+FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U)
+FPU_FCTI(fctiwu, uint32, 0x00000000U)
+FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U)
#if defined(TARGET_PPC64)
-/* fcfid - fcfid. */
-uint64_t helper_fcfid(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.d = int64_to_float64(arg, &env->fp_status);
- return farg.ll;
-}
-
-/* fctid - fctid. */
-uint64_t helper_fctid(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int64(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
-
-/* fctidz - fctidz. */
-uint64_t helper_fctidz(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
+FPU_FCTI(fctid, int64, 0x8000000000000000ULL)
+FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL)
+FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL)
+FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL)
+#endif
- farg.ll = arg;
+#if defined(TARGET_PPC64)
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
+#define FPU_FCFI(op, cvtr, is_single) \
+uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
+{ \
+ CPU_DoubleU farg; \
+ \
+ if (is_single) { \
+ float32 tmp = cvtr(arg, &env->fp_status); \
+ farg.d = float32_to_float64(tmp, &env->fp_status); \
+ } else { \
+ farg.d = cvtr(arg, &env->fp_status); \
+ } \
+ helper_float_check_status(env); \
+ return farg.ll; \
+}
+
+FPU_FCFI(fcfid, int64_to_float64, 0)
+FPU_FCFI(fcfids, int64_to_float32, 1)
+FPU_FCFI(fcfidu, uint64_to_float64, 0)
+FPU_FCFI(fcfidus, uint64_to_float32, 1)
#endif
@@ -706,24 +679,28 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN round */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity round */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ farg.ll = arg | 0x0008000000000000ULL;
} else {
+ int inexact = get_float_exception_flags(&env->fp_status) &
+ float_flag_inexact;
set_float_rounding_mode(rounding_mode, &env->fp_status);
farg.ll = float64_round_to_int(farg.d, &env->fp_status);
/* Restore rounding mode from FPSCR */
fpscr_set_rounding_mode(env);
+
+ /* fri* does not set FPSCR[XX] */
+ if (!inexact) {
+ env->fp_status.float_exception_flags &= ~float_flag_inexact;
+ }
}
+ helper_float_check_status(env);
return farg.ll;
}
uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
{
- return do_fri(env, arg, float_round_nearest_even);
+ return do_fri(env, arg, float_round_ties_away);
}
uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
@@ -754,13 +731,13 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -772,7 +749,7 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -797,13 +774,13 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
(float64_is_zero(farg1.d) &&
float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -815,7 +792,7 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -838,13 +815,13 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -856,7 +833,7 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -883,13 +860,13 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
(float64_is_zero(farg1.d) &&
float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -901,7 +878,7 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -924,7 +901,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
f32 = float64_to_float32(farg.d, &env->fp_status);
farg.d = float32_to_float64(f32, &env->fp_status);
@@ -941,11 +918,11 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_sqrt(farg.d, &env->fp_status);
}
@@ -961,7 +938,7 @@ uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
return farg.d;
@@ -977,7 +954,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
f32 = float64_to_float32(farg.d, &env->fp_status);
@@ -996,11 +973,11 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Reciprocal square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal square root */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_sqrt(farg.d, &env->fp_status);
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
@@ -1026,6 +1003,73 @@ uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
}
}
+uint32_t helper_ftdiv(uint64_t fra, uint64_t frb)
+{
+ int fe_flag = 0;
+ int fg_flag = 0;
+
+ if (unlikely(float64_is_infinity(fra) ||
+ float64_is_infinity(frb) ||
+ float64_is_zero(frb))) {
+ fe_flag = 1;
+ fg_flag = 1;
+ } else {
+ int e_a = ppc_float64_get_unbiased_exp(fra);
+ int e_b = ppc_float64_get_unbiased_exp(frb);
+
+ if (unlikely(float64_is_any_nan(fra) ||
+ float64_is_any_nan(frb))) {
+ fe_flag = 1;
+ } else if ((e_b <= -1022) || (e_b >= 1021)) {
+ fe_flag = 1;
+ } else if (!float64_is_zero(fra) &&
+ (((e_a - e_b) >= 1023) ||
+ ((e_a - e_b) <= -1021) ||
+ (e_a <= -970))) {
+ fe_flag = 1;
+ }
+
+ if (unlikely(float64_is_zero_or_denormal(frb))) {
+ /* XB is not zero because of the above check and */
+ /* so must be denormalized. */
+ fg_flag = 1;
+ }
+ }
+
+ return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
+}
+
+uint32_t helper_ftsqrt(uint64_t frb)
+{
+ int fe_flag = 0;
+ int fg_flag = 0;
+
+ if (unlikely(float64_is_infinity(frb) || float64_is_zero(frb))) {
+ fe_flag = 1;
+ fg_flag = 1;
+ } else {
+ int e_b = ppc_float64_get_unbiased_exp(frb);
+
+ if (unlikely(float64_is_any_nan(frb))) {
+ fe_flag = 1;
+ } else if (unlikely(float64_is_zero(frb))) {
+ fe_flag = 1;
+ } else if (unlikely(float64_is_neg(frb))) {
+ fe_flag = 1;
+ } else if (!float64_is_zero(frb) && (e_b <= (-1022+52))) {
+ fe_flag = 1;
+ }
+
+ if (unlikely(float64_is_zero_or_denormal(frb))) {
+ /* XB is not zero because of the above check and */
+ /* therefore must be denormalized. */
+ fg_flag = 1;
+ }
+ }
+
+ return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
+}
+
void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
uint32_t crfD)
{
@@ -1053,7 +1097,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
&& (float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d)))) {
/* sNaN comparison */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
}
@@ -1085,10 +1129,10 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_signaling_nan(farg2.d)) {
/* sNaN comparison */
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXVC);
+ POWERPC_EXCP_FP_VXVC, 1);
} else {
/* qNaN comparison */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
}
}
}
@@ -1710,3 +1754,969 @@ uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
/* XXX: TODO: test special values (NaN, infinites, ...) */
return helper_efdtsteq(env, op1, op2);
}
+
+#define DECODE_SPLIT(opcode, shift1, nb1, shift2, nb2) \
+ (((((opcode) >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \
+ (((opcode) >> (shift2)) & ((1 << (nb2)) - 1)))
+
+#define xT(opcode) DECODE_SPLIT(opcode, 0, 1, 21, 5)
+#define xA(opcode) DECODE_SPLIT(opcode, 2, 1, 16, 5)
+#define xB(opcode) DECODE_SPLIT(opcode, 1, 1, 11, 5)
+#define xC(opcode) DECODE_SPLIT(opcode, 3, 1, 6, 5)
+#define BF(opcode) (((opcode) >> (31-8)) & 7)
+
+typedef union _ppc_vsr_t {
+ uint64_t u64[2];
+ uint32_t u32[4];
+ float32 f32[4];
+ float64 f64[2];
+} ppc_vsr_t;
+
+static void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
+{
+ if (n < 32) {
+ vsr->f64[0] = env->fpr[n];
+ vsr->u64[1] = env->vsr[n];
+ } else {
+ vsr->u64[0] = env->avr[n-32].u64[0];
+ vsr->u64[1] = env->avr[n-32].u64[1];
+ }
+}
+
+static void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
+{
+ if (n < 32) {
+ env->fpr[n] = vsr->f64[0];
+ env->vsr[n] = vsr->u64[1];
+ } else {
+ env->avr[n-32].u64[0] = vsr->u64[0];
+ env->avr[n-32].u64[1] = vsr->u64[1];
+ }
+}
+
+#define float64_to_float64(x, env) x
+
+
+/* VSX_ADD_SUB - VSX floating point add/subract
+ * name - instruction mnemonic
+ * op - operation (add or sub)
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \
+void helper_##name(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) {\
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \
+ } else if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_ADD_SUB(xsadddp, add, 1, float64, f64, 1, 0)
+VSX_ADD_SUB(xsaddsp, add, 1, float64, f64, 1, 1)
+VSX_ADD_SUB(xvadddp, add, 2, float64, f64, 0, 0)
+VSX_ADD_SUB(xvaddsp, add, 4, float32, f32, 0, 0)
+VSX_ADD_SUB(xssubdp, sub, 1, float64, f64, 1, 0)
+VSX_ADD_SUB(xssubsp, sub, 1, float64, f64, 1, 1)
+VSX_ADD_SUB(xvsubdp, sub, 2, float64, f64, 0, 0)
+VSX_ADD_SUB(xvsubsp, sub, 4, float32, f32, 0, 0)
+
+/* VSX_MUL - VSX floating point multiply
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_mul(xa.fld[i], xb.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(xb.fld[i])) || \
+ (tp##_is_infinity(xb.fld[i]) && tp##_is_zero(xa.fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \
+ } else if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_MUL(xsmuldp, 1, float64, f64, 1, 0)
+VSX_MUL(xsmulsp, 1, float64, f64, 1, 1)
+VSX_MUL(xvmuldp, 2, float64, f64, 0, 0)
+VSX_MUL(xvmulsp, 4, float32, f32, 0, 0)
+
+/* VSX_DIV - VSX floating point divide
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_div(xa.fld[i], xb.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \
+ } else if (tp##_is_zero(xa.fld[i]) && \
+ tp##_is_zero(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \
+ } else if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_DIV(xsdivdp, 1, float64, f64, 1, 0)
+VSX_DIV(xsdivsp, 1, float64, f64, 1, 1)
+VSX_DIV(xvdivdp, 2, float64, f64, 0, 0)
+VSX_DIV(xvdivsp, 4, float32, f32, 0, 0)
+
+/* VSX_RE - VSX floating point reciprocal estimate
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ xt.fld[i] = tp##_div(tp##_one, xb.fld[i], &env->fp_status); \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[0], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_RE(xsredp, 1, float64, f64, 1, 0)
+VSX_RE(xsresp, 1, float64, f64, 1, 1)
+VSX_RE(xvredp, 2, float64, f64, 0, 0)
+VSX_RE(xvresp, 4, float32, f32, 0, 0)
+
+/* VSX_SQRT - VSX floating point square root
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \
+ } else if (tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_SQRT(xssqrtdp, 1, float64, f64, 1, 0)
+VSX_SQRT(xssqrtsp, 1, float64, f64, 1, 1)
+VSX_SQRT(xvsqrtdp, 2, float64, f64, 0, 0)
+VSX_SQRT(xvsqrtsp, 4, float32, f32, 0, 0)
+
+/* VSX_RSQRTE - VSX floating point reciprocal square root estimate
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \
+ xt.fld[i] = tp##_div(tp##_one, xt.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \
+ } else if (tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_RSQRTE(xsrsqrtedp, 1, float64, f64, 1, 0)
+VSX_RSQRTE(xsrsqrtesp, 1, float64, f64, 1, 1)
+VSX_RSQRTE(xvrsqrtedp, 2, float64, f64, 0, 0)
+VSX_RSQRTE(xvrsqrtesp, 4, float32, f32, 0, 0)
+
+/* VSX_TDIV - VSX floating point test for divide
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * emin - minimum unbiased exponent
+ * emax - maximum unbiased exponent
+ * nbits - number of fraction bits
+ */
+#define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xa, xb; \
+ int i; \
+ int fe_flag = 0; \
+ int fg_flag = 0; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_infinity(xa.fld[i]) || \
+ tp##_is_infinity(xb.fld[i]) || \
+ tp##_is_zero(xb.fld[i]))) { \
+ fe_flag = 1; \
+ fg_flag = 1; \
+ } else { \
+ int e_a = ppc_##tp##_get_unbiased_exp(xa.fld[i]); \
+ int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \
+ \
+ if (unlikely(tp##_is_any_nan(xa.fld[i]) || \
+ tp##_is_any_nan(xb.fld[i]))) { \
+ fe_flag = 1; \
+ } else if ((e_b <= emin) || (e_b >= (emax-2))) { \
+ fe_flag = 1; \
+ } else if (!tp##_is_zero(xa.fld[i]) && \
+ (((e_a - e_b) >= emax) || \
+ ((e_a - e_b) <= (emin+1)) || \
+ (e_a <= (emin+nbits)))) { \
+ fe_flag = 1; \
+ } \
+ \
+ if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \
+ /* XB is not zero because of the above check and */ \
+ /* so must be denormalized. */ \
+ fg_flag = 1; \
+ } \
+ } \
+ } \
+ \
+ env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
+}
+
+VSX_TDIV(xstdivdp, 1, float64, f64, -1022, 1023, 52)
+VSX_TDIV(xvtdivdp, 2, float64, f64, -1022, 1023, 52)
+VSX_TDIV(xvtdivsp, 4, float32, f32, -126, 127, 23)
+
+/* VSX_TSQRT - VSX floating point test for square root
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * emin - minimum unbiased exponent
+ * emax - maximum unbiased exponent
+ * nbits - number of fraction bits
+ */
+#define VSX_TSQRT(op, nels, tp, fld, emin, nbits) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xa, xb; \
+ int i; \
+ int fe_flag = 0; \
+ int fg_flag = 0; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_infinity(xb.fld[i]) || \
+ tp##_is_zero(xb.fld[i]))) { \
+ fe_flag = 1; \
+ fg_flag = 1; \
+ } else { \
+ int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \
+ \
+ if (unlikely(tp##_is_any_nan(xb.fld[i]))) { \
+ fe_flag = 1; \
+ } else if (unlikely(tp##_is_zero(xb.fld[i]))) { \
+ fe_flag = 1; \
+ } else if (unlikely(tp##_is_neg(xb.fld[i]))) { \
+ fe_flag = 1; \
+ } else if (!tp##_is_zero(xb.fld[i]) && \
+ (e_b <= (emin+nbits))) { \
+ fe_flag = 1; \
+ } \
+ \
+ if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \
+ /* XB is not zero because of the above check and */ \
+ /* therefore must be denormalized. */ \
+ fg_flag = 1; \
+ } \
+ } \
+ } \
+ \
+ env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
+}
+
+VSX_TSQRT(xstsqrtdp, 1, float64, f64, -1022, 52)
+VSX_TSQRT(xvtsqrtdp, 2, float64, f64, -1022, 52)
+VSX_TSQRT(xvtsqrtsp, 4, float32, f32, -126, 23)
+
+/* VSX_MADD - VSX floating point muliply/add variations
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * maddflgs - flags for the float*muladd routine that control the
+ * various forms (madd, msub, nmadd, nmsub)
+ * afrm - A form (1=A, 0=M)
+ * sfprf - set FPRF
+ */
+#define VSX_MADD(op, nels, tp, fld, maddflgs, afrm, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt_in, xa, xb, xt_out; \
+ ppc_vsr_t *b, *c; \
+ int i; \
+ \
+ if (afrm) { /* AxB + T */ \
+ b = &xb; \
+ c = &xt_in; \
+ } else { /* AxT + B */ \
+ b = &xt_in; \
+ c = &xb; \
+ } \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt_in, env); \
+ \
+ xt_out = xt_in; \
+ \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ if (r2sp && (tstat.float_rounding_mode == float_round_nearest_even)) {\
+ /* Avoid double rounding errors by rounding the intermediate */ \
+ /* result to odd. */ \
+ set_float_rounding_mode(float_round_to_zero, &tstat); \
+ xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \
+ maddflgs, &tstat); \
+ xt_out.fld[i] |= (get_float_exception_flags(&tstat) & \
+ float_flag_inexact) != 0; \
+ } else { \
+ xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \
+ maddflgs, &tstat); \
+ } \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(b->fld[i]) || \
+ tp##_is_signaling_nan(c->fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ tstat.float_exception_flags &= ~float_flag_invalid; \
+ } \
+ if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(b->fld[i])) || \
+ (tp##_is_zero(xa.fld[i]) && tp##_is_infinity(b->fld[i]))) { \
+ xt_out.fld[i] = float64_to_##tp(fload_invalid_op_excp(env, \
+ POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status); \
+ tstat.float_exception_flags &= ~float_flag_invalid; \
+ } \
+ if ((tstat.float_exception_flags & float_flag_invalid) && \
+ ((tp##_is_infinity(xa.fld[i]) || \
+ tp##_is_infinity(b->fld[i])) && \
+ tp##_is_infinity(c->fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt_out.fld[i] = helper_frsp(env, xt_out.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt_out.fld[i], sfprf); \
+ } \
+ } \
+ putVSR(xT(opcode), &xt_out, env); \
+ helper_float_check_status(env); \
+}
+
+#define MADD_FLGS 0
+#define MSUB_FLGS float_muladd_negate_c
+#define NMADD_FLGS float_muladd_negate_result
+#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
+
+VSX_MADD(xsmaddadp, 1, float64, f64, MADD_FLGS, 1, 1, 0)
+VSX_MADD(xsmaddmdp, 1, float64, f64, MADD_FLGS, 0, 1, 0)
+VSX_MADD(xsmsubadp, 1, float64, f64, MSUB_FLGS, 1, 1, 0)
+VSX_MADD(xsmsubmdp, 1, float64, f64, MSUB_FLGS, 0, 1, 0)
+VSX_MADD(xsnmaddadp, 1, float64, f64, NMADD_FLGS, 1, 1, 0)
+VSX_MADD(xsnmaddmdp, 1, float64, f64, NMADD_FLGS, 0, 1, 0)
+VSX_MADD(xsnmsubadp, 1, float64, f64, NMSUB_FLGS, 1, 1, 0)
+VSX_MADD(xsnmsubmdp, 1, float64, f64, NMSUB_FLGS, 0, 1, 0)
+
+VSX_MADD(xsmaddasp, 1, float64, f64, MADD_FLGS, 1, 1, 1)
+VSX_MADD(xsmaddmsp, 1, float64, f64, MADD_FLGS, 0, 1, 1)
+VSX_MADD(xsmsubasp, 1, float64, f64, MSUB_FLGS, 1, 1, 1)
+VSX_MADD(xsmsubmsp, 1, float64, f64, MSUB_FLGS, 0, 1, 1)
+VSX_MADD(xsnmaddasp, 1, float64, f64, NMADD_FLGS, 1, 1, 1)
+VSX_MADD(xsnmaddmsp, 1, float64, f64, NMADD_FLGS, 0, 1, 1)
+VSX_MADD(xsnmsubasp, 1, float64, f64, NMSUB_FLGS, 1, 1, 1)
+VSX_MADD(xsnmsubmsp, 1, float64, f64, NMSUB_FLGS, 0, 1, 1)
+
+VSX_MADD(xvmaddadp, 2, float64, f64, MADD_FLGS, 1, 0, 0)
+VSX_MADD(xvmaddmdp, 2, float64, f64, MADD_FLGS, 0, 0, 0)
+VSX_MADD(xvmsubadp, 2, float64, f64, MSUB_FLGS, 1, 0, 0)
+VSX_MADD(xvmsubmdp, 2, float64, f64, MSUB_FLGS, 0, 0, 0)
+VSX_MADD(xvnmaddadp, 2, float64, f64, NMADD_FLGS, 1, 0, 0)
+VSX_MADD(xvnmaddmdp, 2, float64, f64, NMADD_FLGS, 0, 0, 0)
+VSX_MADD(xvnmsubadp, 2, float64, f64, NMSUB_FLGS, 1, 0, 0)
+VSX_MADD(xvnmsubmdp, 2, float64, f64, NMSUB_FLGS, 0, 0, 0)
+
+VSX_MADD(xvmaddasp, 4, float32, f32, MADD_FLGS, 1, 0, 0)
+VSX_MADD(xvmaddmsp, 4, float32, f32, MADD_FLGS, 0, 0, 0)
+VSX_MADD(xvmsubasp, 4, float32, f32, MSUB_FLGS, 1, 0, 0)
+VSX_MADD(xvmsubmsp, 4, float32, f32, MSUB_FLGS, 0, 0, 0)
+VSX_MADD(xvnmaddasp, 4, float32, f32, NMADD_FLGS, 1, 0, 0)
+VSX_MADD(xvnmaddmsp, 4, float32, f32, NMADD_FLGS, 0, 0, 0)
+VSX_MADD(xvnmsubasp, 4, float32, f32, NMSUB_FLGS, 1, 0, 0)
+VSX_MADD(xvnmsubmsp, 4, float32, f32, NMSUB_FLGS, 0, 0, 0)
+
+#define VSX_SCALAR_CMP(op, ordered) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xa, xb; \
+ uint32_t cc = 0; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ \
+ if (unlikely(float64_is_any_nan(xa.f64[0]) || \
+ float64_is_any_nan(xb.f64[0]))) { \
+ if (float64_is_signaling_nan(xa.f64[0]) || \
+ float64_is_signaling_nan(xb.f64[0])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ if (ordered) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
+ } \
+ cc = 1; \
+ } else { \
+ if (float64_lt(xa.f64[0], xb.f64[0], &env->fp_status)) { \
+ cc = 8; \
+ } else if (!float64_le(xa.f64[0], xb.f64[0], &env->fp_status)) { \
+ cc = 4; \
+ } else { \
+ cc = 2; \
+ } \
+ } \
+ \
+ env->fpscr &= ~(0x0F << FPSCR_FPRF); \
+ env->fpscr |= cc << FPSCR_FPRF; \
+ env->crf[BF(opcode)] = cc; \
+ \
+ helper_float_check_status(env); \
+}
+
+VSX_SCALAR_CMP(xscmpodp, 1)
+VSX_SCALAR_CMP(xscmpudp, 0)
+
+#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
+#define float32_snan_to_qnan(x) ((x) | 0x00400000)
+
+/* VSX_MAX_MIN - VSX floating point maximum/minimum
+ * name - instruction mnemonic
+ * op - operation (max or min)
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ */
+#define VSX_MAX_MIN(name, op, nels, tp, fld) \
+void helper_##name(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &env->fp_status); \
+ if (unlikely(tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, f64)
+VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, f64)
+VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, f32)
+VSX_MAX_MIN(xsmindp, minnum, 1, float64, f64)
+VSX_MAX_MIN(xvmindp, minnum, 2, float64, f64)
+VSX_MAX_MIN(xvminsp, minnum, 4, float32, f32)
+
+/* VSX_CMP - VSX floating point compare
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * cmp - comparison operation
+ * svxvc - set VXVC bit
+ */
+#define VSX_CMP(op, nels, tp, fld, cmp, svxvc) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ int all_true = 1; \
+ int all_false = 1; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_any_nan(xa.fld[i]) || \
+ tp##_is_any_nan(xb.fld[i]))) { \
+ if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ if (svxvc) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
+ } \
+ xt.fld[i] = 0; \
+ all_true = 0; \
+ } else { \
+ if (tp##_##cmp(xb.fld[i], xa.fld[i], &env->fp_status) == 1) { \
+ xt.fld[i] = -1; \
+ all_false = 0; \
+ } else { \
+ xt.fld[i] = 0; \
+ all_true = 0; \
+ } \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ if ((opcode >> (31-21