[Spice-commits] 370 commits - CODING_STYLE MAINTAINERS Makefile Makefile.objs Makefile.target QMP/qmp-spec.txt arch_init.c block.c block.h block/blkdebug.c block/cow.c block/curl.c block/qcow.c block/qcow2-cluster.c block/qcow2.c block/qed-check.c block/qed.c block/qed.h block/raw.c block/sheepdog.c block/stream.c block/vdi.c block/vmdk.c block/vpc.c block_int.h blockdev.c bsd-user/main.c check-qdict.c check-qfloat.c check-qint.c check-qjson.c check-qlist.c check-qstring.c configure coroutine-gthread.c cpu-all.h cpu-defs.h cpu-exec.c cpus.c cpus.h def-helper.h dis-asm.h disas.c dma-helpers.c dma.h docs/ccid.txt docs/qapi-code-gen.txt docs/specs elf.h exec-all.h exec.c fpu/softfloat.c fsdev/virtfs-proxy-helper.texi gdbstub.c hmp-commands.hx hmp.c hmp.h hw/a15mpcore.c hw/a9mpcore.c hw/acpi_piix4.c hw/arm11mpcore.c hw/arm_gic.c hw/armv7m_nvic.c hw/blizzard.c hw/eepro100.c hw/exynos4210.c hw/exynos4210.h hw/exynos4210_combiner.c hw/exynos4210_gic.c hw/exynos4210_uart.c hw/exynos4_boards .c hw/ide hw/irq.c hw/irq.h hw/ivshmem.c hw/kvm hw/lsi53c895a.c hw/mc146818rtc.c hw/mc146818rtc.h hw/mc146818rtc_regs.h hw/milkymist-sysctl.c hw/milkymist-vgafb.c hw/ne2000.c hw/omap1.c hw/omap_lcdc.c hw/opencores_eth.c hw/pc.c hw/pc_piix.c hw/pci-hotplug.c hw/pci.c hw/pci.h hw/pci_bridge.c hw/pci_bridge_dev.c hw/pci_host.c hw/pci_regs.h hw/pcie_port.c hw/pcnet.c hw/pcnet.h hw/petalogix_s3adsp1800_mmu.c hw/piix_pci.c hw/pl031.c hw/ppc440_bamboo.c hw/ppc_prep.c hw/ppce500_mpc8544ds.c hw/ps2.c hw/ps2.h hw/pxa2xx.c hw/qdev-monitor.c hw/qdev-properties.c hw/qdev.c hw/qdev.h hw/realview_gic.c hw/rtl8139.c hw/serial.c hw/shpc.c hw/shpc.h hw/slotid_cap.c hw/slotid_cap.h hw/spapr.h hw/spapr_llan.c hw/spapr_pci.c hw/spapr_rtas.c hw/spapr_vio.c hw/spapr_vio.h hw/spapr_vscsi.c hw/spapr_vty.c hw/strongarm.c hw/sun4m.c hw/sun4u.c hw/twl92230.c hw/usb hw/vga.c hw/vhost.c hw/virtio-net.h hw/virtio-pci.c hw/xen.h hw/xen_apic.c hw/xen_backend.c hw/xen_console.c hw/xen_disk.c hw/xen_platform. c include/qemu ioport.c kvm-all.c kvm-stub.c kvm.h libcacard/vcard_emul_nss.c linux-aio.c linux-headers/asm-powerpc linux-headers/asm-s390 linux-headers/linux linux-user/arm linux-user/elfload.c linux-user/ioctls.h linux-user/main.c linux-user/mmap.c linux-user/qemu.h linux-user/syscall.c linux-user/syscall_defs.h linux-user/syscall_types.h lm32-dis.c main-loop.c main-loop.h memory.c migration.c monitor.c nbd.c net.c net.h osdep.h oslib-win32.c pc-bios/optionrom ppc-dis.c qapi-schema-test.json qapi-schema.json qapi/qmp-input-visitor.c qapi/qmp-input-visitor.h qapi/qmp-output-visitor.c qemu-aio.h qemu-char.c qemu-common.h qemu-doc.texi qemu-img.c qemu-io.c qemu-nbd.texi qemu-options.hx qemu-os-win32.h qemu-queue.h qemu-timer.c qemu-timer.h qemu_socket.h qerror.c qerror.h qga/commands-posix.c qmp-commands.hx qom/container.c qom/object.c qtest.c qtest.h rules.mak savevm.c scripts/create_config scripts/gtester-cat scripts/kvm scripts/qapi-commands.py scripts/qapi-types.py script s/qapi-visit.py scripts/qapi.py scripts/qemu-gdb.py scripts/qtest scripts/signrom.py scripts/signrom.sh scripts/texi2pod.pl scripts/tracetool slirp/misc.c slirp/sbuf.c slirp/slirp.h slirp/tcp.h slirp/tcp_subr.c softmmu_header.h softmmu_template.h target-alpha/STATUS target-alpha/cpu-qom.h target-alpha/cpu.c target-alpha/cpu.h target-alpha/fpu_helper.c target-alpha/helper.c target-alpha/helper.h target-alpha/int_helper.c target-alpha/mem_helper.c target-alpha/op_helper.c target-alpha/sys_helper.c target-alpha/translate.c target-arm/cpu-qom.h target-arm/cpu.c target-arm/cpu.h target-arm/helper.c target-arm/op_helper.c target-arm/translate.c target-cris/op_helper.c target-i386/cpu-qom.h target-i386/cpu.c target-i386/cpu.h target-i386/cpuid.c target-i386/helper.c target-i386/op_helper.c target-lm32/cpu-qom.h target-lm32/cpu.c target-lm32/cpu.h target-lm32/helper.c target-lm32/op_helper.c target-m68k/op_helper.c target-microblaze/helper.c target-microblaze/mmu.c target-microblaze /op_helper.c target-microblaze/translate.c target-mips/TODO target-mips/cpu.h target-mips/helper.h target-mips/op_helper.c target-ppc/cpu-qom.h target-ppc/cpu.h target-ppc/helper.c target-ppc/kvm.c target-ppc/kvm_ppc.c target-ppc/kvm_ppc.h target-ppc/machine.c target-ppc/op_helper.c target-ppc/translate.c target-ppc/translate_init.c target-s390x/cpu-qom.h target-s390x/cpu.c target-s390x/cpu.h target-s390x/helper.c target-s390x/op_helper.c target-sh4/op_helper.c target-sparc/cpu-qom.h target-sparc/cpu.c target-sparc/cpu.h target-sparc/cpu_init.c target-sparc/helper.h target-sparc/ldst_helper.c target-sparc/mmu_helper.c target-unicore32/cpu-qom.h target-unicore32/cpu.c target-unicore32/cpu.h target-unicore32/helper.c target-unicore32/helper.h target-unicore32/op_helper.c target-unicore32/translate.c target-xtensa/core-dc232b.c target-xtensa/core-dc233c target-xtensa/core-dc233c.c target-xtensa/core-fsf.c target-xtensa/cpu-qom.h target-xtensa/cpu.c target-xtensa/cpu.h target-xt ensa/helper.c target-xtensa/helper.h target-xtensa/helpers.h target-xtensa/op_helper.c target-xtensa/translate.c tcg/hppa tcg/i386 tcg/ppc64 tcg/sparc tcg/tcg.c tcg/tcg.h tci.c test-coroutine.c test-qmp-commands.c test-qmp-input-visitor.c test-qmp-output-visitor.c test-string-input-visitor.c test-string-output-visitor.c tests/Makefile tests/check-qdict.c tests/check-qfloat.c tests/check-qint.c tests/check-qjson.c tests/check-qlist.c tests/check-qstring.c tests/libqtest.c tests/libqtest.h tests/qemu-iotests tests/rtc-test.c tests/tcg tests/test-coroutine.c tests/test-qmp-commands.c tests/test-qmp-input-strict.c tests/test-qmp-input-visitor.c tests/test-qmp-output-visitor.c tests/test-string-input-visitor.c tests/test-string-output-visitor.c thunk.c thunk.h trace-events translate-all.c ui/cocoa.m ui/spice-display.c user-exec.c vl.c xen-all.c xen-mapcache.c xen-stub.c xtensa-semi.c
Gerd Hoffmann
kraxel at kemper.freedesktop.org
Wed Apr 18 03:20:17 PDT 2012
CODING_STYLE | 2
MAINTAINERS | 5
Makefile | 12
Makefile.objs | 7
Makefile.target | 19
QMP/qmp-spec.txt | 20
arch_init.c | 2
block.c | 88 +
block.h | 21
block/blkdebug.c | 7
block/cow.c | 6
block/curl.c | 2
block/qcow.c | 6
block/qcow2-cluster.c | 18
block/qcow2.c | 6
block/qed-check.c | 9
block/qed.c | 33
block/qed.h | 2
block/raw.c | 6
block/sheepdog.c | 144 ++-
block/stream.c | 41
block/vdi.c | 429 ++-------
block/vmdk.c | 4
block/vpc.c | 9
block_int.h | 135 ++
blockdev.c | 12
bsd-user/main.c | 1
check-qdict.c | 378 --------
check-qfloat.c | 53 -
check-qint.c | 87 -
check-qjson.c | 728 ---------------
check-qlist.c | 127 --
check-qstring.c | 107 --
configure | 65 +
coroutine-gthread.c | 96 +-
cpu-all.h | 15
cpu-defs.h | 14
cpu-exec.c | 5
cpus.c | 85 +
cpus.h | 2
def-helper.h | 7
dis-asm.h | 3
disas.c | 32
dma-helpers.c | 21
dma.h | 13
docs/ccid.txt | 2
docs/qapi-code-gen.txt | 4
docs/specs/acpi_pci_hotplug.txt | 18
docs/specs/ivshmem_device_spec.txt | 2
elf.h | 37
exec-all.h | 40
exec.c | 112 +-
fpu/softfloat.c | 12
fsdev/virtfs-proxy-helper.texi | 2
gdbstub.c | 42
hmp-commands.hx | 3
hmp.c | 9
hmp.h | 1
hw/a15mpcore.c | 46 -
hw/a9mpcore.c | 72 -
hw/acpi_piix4.c | 134 +-
hw/arm11mpcore.c | 56 -
hw/arm_gic.c | 157 ++-
hw/armv7m_nvic.c | 24
hw/blizzard.c | 4
hw/eepro100.c | 25
hw/exynos4210.c | 30
hw/exynos4210.h | 3
hw/exynos4210_combiner.c | 10
hw/exynos4210_gic.c | 48 -
hw/exynos4210_uart.c | 6
hw/exynos4_boards.c | 1
hw/ide/core.c | 60 +
hw/ide/internal.h | 7
hw/ide/macio.c | 3
hw/ide/qdev.c | 7
hw/irq.c | 17
hw/irq.h | 5
hw/ivshmem.c | 58 -
hw/kvm/clock.c | 16
hw/lsi53c895a.c | 1
hw/mc146818rtc.c | 33
hw/mc146818rtc.h | 3
hw/mc146818rtc_regs.h | 62 +
hw/milkymist-sysctl.c | 26
hw/milkymist-vgafb.c | 5
hw/ne2000.c | 24
hw/omap1.c | 10
hw/omap_lcdc.c | 5
hw/opencores_eth.c | 25
hw/pc.c | 10
hw/pc_piix.c | 318 +-----
hw/pci-hotplug.c | 14
hw/pci.c | 28
hw/pci.h | 11
hw/pci_bridge.c | 22
hw/pci_bridge_dev.c | 174 +++
hw/pci_host.c | 3
hw/pci_regs.h | 3
hw/pcie_port.c | 12
hw/pcnet.c | 13
hw/pcnet.h | 1
hw/petalogix_s3adsp1800_mmu.c | 1
hw/piix_pci.c | 5
hw/pl031.c | 75 +
hw/ppc440_bamboo.c | 2
hw/ppc_prep.c | 2
hw/ppce500_mpc8544ds.c | 2
hw/ps2.c | 2
hw/ps2.h | 29
hw/pxa2xx.c | 28
hw/qdev-monitor.c | 27
hw/qdev-properties.c | 46 +
hw/qdev.c | 39
hw/qdev.h | 8
hw/realview_gic.c | 46 -
hw/rtl8139.c | 92 +-
hw/serial.c | 5
hw/shpc.c | 681 ++++++++++++++
hw/shpc.h | 48 +
hw/slotid_cap.c | 44
hw/slotid_cap.h | 11
hw/spapr.h | 2
hw/spapr_llan.c | 26
hw/spapr_pci.c | 117 +-
hw/spapr_rtas.c | 17
hw/spapr_vio.c | 62 -
hw/spapr_vio.h | 5
hw/spapr_vscsi.c | 15
hw/spapr_vty.c | 4
hw/strongarm.c | 10
hw/sun4m.c | 12
hw/sun4u.c | 36
hw/twl92230.c | 9
hw/usb/dev-storage.c | 2
hw/vga.c | 2
hw/vhost.c | 10
hw/virtio-net.h | 1
hw/virtio-pci.c | 8
hw/xen.h | 1
hw/xen_apic.c | 90 +
hw/xen_backend.c | 17
hw/xen_console.c | 3
hw/xen_disk.c | 15
hw/xen_platform.c | 4
include/qemu/object.h | 24
ioport.c | 2
kvm-all.c | 23
kvm-stub.c | 8
kvm.h | 5
libcacard/vcard_emul_nss.c | 36
linux-aio.c | 1
linux-headers/asm-powerpc/kvm.h | 1
linux-headers/asm-s390/kvm.h | 2
linux-headers/linux/kvm.h | 9
linux-user/arm/syscall_nr.h | 2
linux-user/elfload.c | 32
linux-user/ioctls.h | 34
linux-user/main.c | 51 -
linux-user/mmap.c | 35
linux-user/qemu.h | 2
linux-user/syscall.c | 307 ++++++
linux-user/syscall_defs.h | 26
linux-user/syscall_types.h | 40
lm32-dis.c | 361 +++++++
main-loop.c | 149 +--
main-loop.h | 1
memory.c | 19
migration.c | 1
monitor.c | 3
nbd.c | 2
net.c | 23
net.h | 3
osdep.h | 2
oslib-win32.c | 3
pc-bios/optionrom/Makefile | 2
ppc-dis.c | 2
qapi-schema-test.json | 2
qapi-schema.json | 20
qapi/qmp-input-visitor.c | 120 +-
qapi/qmp-input-visitor.h | 2
qapi/qmp-output-visitor.c | 8
qemu-aio.h | 21
qemu-char.c | 1
qemu-common.h | 2
qemu-doc.texi | 8
qemu-img.c | 12
qemu-io.c | 10
qemu-nbd.texi | 2
qemu-options.hx | 33
qemu-os-win32.h | 35
qemu-queue.h | 2
qemu-timer.c | 12
qemu-timer.h | 1
qemu_socket.h | 4
qerror.c | 7
qerror.h | 4
qga/commands-posix.c | 111 +-
qmp-commands.hx | 9
qom/container.c | 23
qom/object.c | 33
qtest.c | 444 +++++++++
qtest.h | 35
rules.mak | 2
savevm.c | 3
scripts/create_config | 6
scripts/gtester-cat | 26
scripts/kvm/kvm_flightrecorder | 126 ++
scripts/qapi-commands.py | 16
scripts/qapi-types.py | 4
scripts/qapi-visit.py | 24
scripts/qapi.py | 5
scripts/qemu-gdb.py | 89 +
scripts/qtest | 5
scripts/signrom.py | 40
scripts/signrom.sh | 45
scripts/texi2pod.pl | 9
scripts/tracetool | 30
slirp/misc.c | 46 -
slirp/sbuf.c | 6
slirp/slirp.h | 14
slirp/tcp.h | 21
slirp/tcp_subr.c | 4
softmmu_header.h | 15
softmmu_template.h | 42
target-alpha/STATUS | 2
target-alpha/cpu-qom.h | 71 +
target-alpha/cpu.c | 58 +
target-alpha/cpu.h | 7
target-alpha/fpu_helper.c | 822 ++++++++++++++++++
target-alpha/helper.c | 60 +
target-alpha/helper.h | 143 +--
target-alpha/int_helper.c | 319 +++++++
target-alpha/mem_helper.c | 151 +++
target-alpha/op_helper.c | 1379 ------------------------------
target-alpha/sys_helper.c | 87 +
target-alpha/translate.c | 234 ++---
target-arm/cpu-qom.h | 71 +
target-arm/cpu.c | 60 +
target-arm/cpu.h | 35
target-arm/helper.c | 23
target-arm/op_helper.c | 8
target-arm/translate.c | 13
target-cris/op_helper.c | 12
target-i386/cpu-qom.h | 75 +
target-i386/cpu.c | 1503 +++++++++++++++++++++++++++++++++
target-i386/cpu.h | 3
target-i386/cpuid.c | 1369 ------------------------------
target-i386/helper.c | 100 --
target-i386/op_helper.c | 8
target-lm32/cpu-qom.h | 71 +
target-lm32/cpu.c | 81 +
target-lm32/cpu.h | 1
target-lm32/helper.c | 19
target-lm32/op_helper.c | 8
target-m68k/op_helper.c | 8
target-microblaze/helper.c | 1
target-microblaze/mmu.c | 1
target-microblaze/op_helper.c | 9
target-microblaze/translate.c | 1
target-mips/TODO | 4
target-mips/cpu.h | 2
target-mips/helper.h | 4
target-mips/op_helper.c | 21
target-ppc/cpu-qom.h | 77 +
target-ppc/cpu.h | 9
target-ppc/helper.c | 75 -
target-ppc/kvm.c | 16
target-ppc/kvm_ppc.c | 2
target-ppc/kvm_ppc.h | 5
target-ppc/machine.c | 8
target-ppc/op_helper.c | 8
target-ppc/translate.c | 2
target-ppc/translate_init.c | 176 +++
target-s390x/cpu-qom.h | 71 +
target-s390x/cpu.c | 96 ++
target-s390x/cpu.h | 5
target-s390x/helper.c | 41
target-s390x/op_helper.c | 8
target-sh4/op_helper.c | 14
target-sparc/cpu-qom.h | 75 +
target-sparc/cpu.c | 899 +++++++++++++++++++
target-sparc/cpu.h | 6
target-sparc/cpu_init.c | 849 ------------------
target-sparc/helper.h | 2
target-sparc/ldst_helper.c | 12
target-sparc/mmu_helper.c | 19
target-unicore32/cpu-qom.h | 59 +
target-unicore32/cpu.c | 104 ++
target-unicore32/cpu.h | 4
target-unicore32/helper.c | 65 -
target-unicore32/helper.h | 3
target-unicore32/op_helper.c | 3
target-unicore32/translate.c | 3
target-xtensa/core-dc232b.c | 27
target-xtensa/core-dc233c.c | 55 +
target-xtensa/core-dc233c/core-isa.h | 474 ++++++++++
target-xtensa/core-dc233c/gdb-config.c | 145 +++
target-xtensa/core-fsf.c | 27
target-xtensa/cpu-qom.h | 80 +
target-xtensa/cpu.c | 88 +
target-xtensa/cpu.h | 2
target-xtensa/helper.c | 20
target-xtensa/helper.h | 39
target-xtensa/helpers.h | 39
target-xtensa/op_helper.c | 40
target-xtensa/translate.c | 8
tcg/hppa/tcg-target.c | 103 +-
tcg/i386/tcg-target.c | 157 +++
tcg/ppc64/tcg-target.c | 1
tcg/sparc/tcg-target.c | 63 +
tcg/tcg.c | 283 ++++++
tcg/tcg.h | 2
tci.c | 35
test-coroutine.c | 219 ----
test-qmp-commands.c | 142 ---
test-qmp-input-visitor.c | 289 ------
test-qmp-output-visitor.c | 457 ----------
test-string-input-visitor.c | 195 ----
test-string-output-visitor.c | 188 ----
tests/Makefile | 164 ++-
tests/check-qdict.c | 378 ++++++++
tests/check-qfloat.c | 53 +
tests/check-qint.c | 87 +
tests/check-qjson.c | 728 +++++++++++++++
tests/check-qlist.c | 127 ++
tests/check-qstring.c | 107 ++
tests/libqtest.c | 387 ++++++++
tests/libqtest.h | 335 +++++++
tests/qemu-iotests/009 | 4
tests/qemu-iotests/010 | 6
tests/qemu-iotests/011 | 2
tests/qemu-iotests/031 | 72 +
tests/qemu-iotests/031.out | 76 +
tests/qemu-iotests/common.rc | 9
tests/qemu-iotests/group | 1
tests/qemu-iotests/qcow2.py | 207 ++++
tests/rtc-test.c | 263 +++++
tests/tcg/lm32/Makefile | 13
tests/tcg/xtensa/Makefile | 3
tests/tcg/xtensa/macros.inc | 17
tests/tcg/xtensa/test_break.S | 34
tests/tcg/xtensa/test_loop.S | 50 +
tests/test-coroutine.c | 219 ++++
tests/test-qmp-commands.c | 139 +++
tests/test-qmp-input-strict.c | 234 +++++
tests/test-qmp-input-visitor.c | 308 ++++++
tests/test-qmp-output-visitor.c | 477 ++++++++++
tests/test-string-input-visitor.c | 195 ++++
tests/test-string-output-visitor.c | 188 ++++
thunk.c | 28
thunk.h | 28
trace-events | 4
translate-all.c | 6
ui/cocoa.m | 2
ui/spice-display.c | 24
user-exec.c | 2
vl.c | 14
xen-all.c | 50 -
xen-mapcache.c | 15
xen-stub.c | 4
xtensa-semi.c | 2
362 files changed, 17570 insertions(+), 9401 deletions(-)
New commits:
commit 158fd3ce98afd21f2e2639600f6414ea703a9121
Author: Peter Portante <peter.portante at redhat.com>
Date: Thu Apr 5 11:00:45 2012 -0400
qemu-timer.c: Remove 250us timeouts
Basically, the main wait loop calls qemu_run_all_timers() unconditionally. The
first thing this routine used to do is to see if a timer had been serviced,
and then reset the loop timeout to the next deadline.
However, the new deadlines had not been calculated at that point, as
qemu_run_timers() had not been called yet for each of the clocks. So
qemu_rearm_alarm_timer() would end up with a negative or zero deadline, and
default to setting a 250us timeout for the loop.
As qemu_run_timers() is called for each clock, the real deadlines would be put
in place, but because a loop timeout was already set, the loop timeout would
not be changed.
Once that 250us timeout fired, the real deadline would be used for the
subsequent timeout.
For idle VMs, this effectively doubles the number of times through the loop,
doubling the number of select() system calls, timer calls, etc. putting added
scheduling pressure on the kernel. And under cgroups, this really causes a big
problem because the cgroup code does not scale well.
By simply running the timers before trying to rearm the timer, we always rearm
with a non-zero deadline, effectively halving the number of system calls.
Signed-off-by: Peter Portante <pportant at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qemu-timer.c b/qemu-timer.c
index 80bcc56..17915df 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -472,16 +472,16 @@ void qemu_run_all_timers(void)
{
alarm_timer->pending = 0;
+ /* vm time timers */
+ qemu_run_timers(vm_clock);
+ qemu_run_timers(rt_clock);
+ qemu_run_timers(host_clock);
+
/* rearm timer, if not periodic */
if (alarm_timer->expired) {
alarm_timer->expired = 0;
qemu_rearm_alarm_timer(alarm_timer);
}
-
- /* vm time timers */
- qemu_run_timers(vm_clock);
- qemu_run_timers(rt_clock);
- qemu_run_timers(host_clock);
}
#ifdef _WIN32
commit fc34e77bb3dd41a9932ec5830c06bcade1f5a08e
Merge: 52346e8... 9bea6a2...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 16 12:56:28 2012 -0500
Merge remote-tracking branch 'kiszka/queues/pending' into staging
* kiszka/queues/pending:
vapic: Disable for pre-1.1 machines
Kick io-thread on qemu_chr_accept_input
pcnet: Properly handle TX requests during Link Fail
pcnet: Clear ERR in CSR0 on stop
signrom: Rewrite as python script
Conflicts:
hw/pc_piix.c
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --cc hw/pc_piix.c
index 5c08245,44995bf..907d723
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@@ -360,21 -359,6 +360,25 @@@ static QEMUMachine pc_machine_v1_1 =
.is_default = 1,
};
+#define PC_COMPAT_1_0 \
+ {\
+ .driver = "pc-sysfw",\
+ .property = "rom_only",\
+ .value = stringify(1),\
+ }, {\
+ .driver = "isa-fdc",\
+ .property = "check_media_rate",\
+ .value = "off",\
+ }, {\
+ .driver = "virtio-balloon-pci",\
+ .property = "class",\
+ .value = stringify(PCI_CLASS_MEMORY_RAM),\
++ },{\
++ .driver = "apic",\
++ .property = "vapic",\
++ .value = "off",\
+ }
+
static QEMUMachine pc_machine_v1_0 = {
.name = "pc-1.0",
.desc = "Standard PC",
commit 52346e8c75eba1ece4a782565d5a5ce2e23d5117
Merge: 8a6b870... cdde6ff...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 16 12:52:22 2012 -0500
Merge remote-tracking branch 'mst/tags/for_anthony' into staging
* mst/tags/for_anthony:
pci: fix corrupted pci conf index register by unaligned write
acpi: explicitly account for >1 device per slot
acpi_piix4: Re-define PCI hotplug eject register read
acpi_piix4: Remove PCI_RMV_BASE write code
acpi_piix4: Fix PCI hotplug race
acpi_piix4: Disallow write to up/down PCI hotplug registers
virtio-pci: change virtio balloon PCI class code
ivshmem: add missing msix calls
vhost: readd assert statement
vhost: Fix size of dirty log sync on resize
pc: reduce duplication in compat machine types
piix_pci: fix typo in i400FX chipset init code
commit 8a6b8708e37a4df064aa3b36d7baa786110871f4
Merge: e6f5d0b... fda1f76...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 16 12:50:12 2012 -0500
Merge remote-tracking branch 'sstabellini/for_anthony' into staging
* sstabellini/for_anthony:
xen: introduce an event channel for buffered io event notifications
xen-mapcache: don't unmap locked entry during mapcache invalidation
Xen, mapcache: Fix the compute of the size of bucket.
xen: handle backend deletion from xenstore
Xen: Add xen-apic support and hook it up.
Xen: basic HVM MSI injection support.
commit 9bea6a2956e5d473b8914b2a5483fbf187b33844
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Thu Mar 29 14:07:46 2012 +0200
vapic: Disable for pre-1.1 machines
The kvmvapic was not present in older QEMU versions, thus must be
disabled in compat machines.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index fadca4c..44995bf 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -373,6 +373,10 @@ static QEMUMachine pc_machine_v1_0 = {
.driver = "isa-fdc",
.property = "check_media_rate",
.value = "off",
+ },{
+ .driver = "apic",
+ .property = "vapic",
+ .value = "off",
},
{ /* end of list */ }
},
@@ -392,6 +396,10 @@ static QEMUMachine pc_machine_v0_15 = {
.driver = "isa-fdc",
.property = "check_media_rate",
.value = "off",
+ },{
+ .driver = "apic",
+ .property = "vapic",
+ .value = "off",
},
{ /* end of list */ }
},
@@ -431,11 +439,14 @@ static QEMUMachine pc_machine_v0_14 = {
.driver = "isa-fdc",
.property = "check_media_rate",
.value = "off",
- },
- {
+ },{
.driver = "pc-sysfw",
.property = "rom_only",
.value = stringify(1),
+ },{
+ .driver = "apic",
+ .property = "vapic",
+ .value = "off",
},
{ /* end of list */ }
},
@@ -487,11 +498,14 @@ static QEMUMachine pc_machine_v0_13 = {
.driver = "isa-fdc",
.property = "check_media_rate",
.value = "off",
- },
- {
+ },{
.driver = "pc-sysfw",
.property = "rom_only",
.value = stringify(1),
+ },{
+ .driver = "apic",
+ .property = "vapic",
+ .value = "off",
},
{ /* end of list */ }
},
@@ -547,11 +561,14 @@ static QEMUMachine pc_machine_v0_12 = {
.driver = "isa-fdc",
.property = "check_media_rate",
.value = "off",
- },
- {
+ },{
.driver = "pc-sysfw",
.property = "rom_only",
.value = stringify(1),
+ },{
+ .driver = "apic",
+ .property = "vapic",
+ .value = "off",
},
{ /* end of list */ }
}
@@ -615,11 +632,14 @@ static QEMUMachine pc_machine_v0_11 = {
.driver = "isa-fdc",
.property = "check_media_rate",
.value = "off",
- },
- {
+ },{
.driver = "pc-sysfw",
.property = "rom_only",
.value = stringify(1),
+ },{
+ .driver = "apic",
+ .property = "vapic",
+ .value = "off",
},
{ /* end of list */ }
}
@@ -695,11 +715,14 @@ static QEMUMachine pc_machine_v0_10 = {
.driver = "isa-fdc",
.property = "check_media_rate",
.value = "off",
- },
- {
+ },{
.driver = "pc-sysfw",
.property = "rom_only",
.value = stringify(1),
+ },{
+ .driver = "apic",
+ .property = "vapic",
+ .value = "off",
},
{ /* end of list */ }
},
commit 98c8ee1da81b88252263f9215ca23b2044650696
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Fri Mar 16 13:18:00 2012 +0100
Kick io-thread on qemu_chr_accept_input
Once a chr frontend is able to receive input again, we need to inform
the io-thread about this fact. Otherwise, main_loop_wait may continue to
select without the related backend file descriptor in its set. This can
cause high input latencies if only low-rate events arrive otherwise.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/qemu-char.c b/qemu-char.c
index bb9e3f5..74c60e1 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -177,6 +177,7 @@ void qemu_chr_accept_input(CharDriverState *s)
{
if (s->chr_accept_input)
s->chr_accept_input(s);
+ qemu_notify_event();
}
void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
commit ef45c9147f534531ef5d8a20315089d43ea4ddef
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Wed Feb 29 15:37:43 2012 +0100
pcnet: Properly handle TX requests during Link Fail
As long as we have no link and we aren't in internal loopback mode, no
packet must be sent. Instead, LCAR needs to be set in any active TX
descriptor and also CERR in CSR0.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 7413409..d769b08 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -77,6 +77,7 @@ struct qemu_ether_header {
#define CSR_DTX(S) !!(((S)->csr[15])&0x0002)
#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004)
#define CSR_DXMTFCS(S) !!(((S)->csr[15])&0x0008)
+#define CSR_INTL(S) !!(((S)->csr[15])&0x0040)
#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)
#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)
#define CSR_PROM(S) !!(((S)->csr[15])&0x8000)
@@ -1234,6 +1235,15 @@ static void pcnet_transmit(PCNetState *s)
if (BCR_SWSTYLE(s) != 1)
add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS);
}
+ if (s->lnkst == 0 &&
+ (!CSR_LOOP(s) || (!CSR_INTL(s) && !BCR_TMAULOOP(s)))) {
+ SET_FIELD(&tmd.misc, TMDM, LCAR, 1);
+ SET_FIELD(&tmd.status, TMDS, ERR, 1);
+ SET_FIELD(&tmd.status, TMDS, OWN, 0);
+ s->csr[0] |= 0xa000; /* ERR | CERR */
+ s->xmit_pos = -1;
+ goto txdone;
+ }
if (!GET_FIELD(tmd.status, TMDS, ENP)) {
int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
@@ -1262,6 +1272,7 @@ static void pcnet_transmit(PCNetState *s)
s->xmit_pos = -1;
}
+ txdone:
SET_FIELD(&tmd.status, TMDS, OWN, 0);
TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
diff --git a/hw/pcnet.h b/hw/pcnet.h
index edc81c9..803a2cc 100644
--- a/hw/pcnet.h
+++ b/hw/pcnet.h
@@ -20,6 +20,7 @@
#define BCR_SWS 20
#define BCR_PLAT 22
+#define BCR_TMAULOOP(S) !!((S)->bcr[BCR_MC ] & 0x4000)
#define BCR_APROMWE(S) !!((S)->bcr[BCR_MC ] & 0x0100)
#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080)
#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100)
commit 6655124ddd6442b19a4b43b27e7d5a3846c4e6a8
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Wed Feb 29 15:33:48 2012 +0100
pcnet: Clear ERR in CSR0 on stop
pcnet_stop already clears any reason (BABL, CERR, MISS, MERR) why ERR
(bit 15) should be set in CRS0. So we have to clear that bit as well.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/hw/pcnet.c b/hw/pcnet.c
index c53f06e..7413409 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -884,7 +884,7 @@ static void pcnet_stop(PCNetState *s)
#ifdef PCNET_DEBUG
printf("pcnet_stop\n");
#endif
- s->csr[0] &= ~0x7feb;
+ s->csr[0] &= ~0xffeb;
s->csr[0] |= 0x0014;
s->csr[4] &= ~0x02c2;
s->csr[5] &= ~0x0011;
commit 0d6b9cc7420dd2d531b48508f0d4083d1c6a632a
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Fri Jan 27 19:44:53 2012 +0100
signrom: Rewrite as python script
Now that we have a hard dependency on python anyway, we can replace the
slow shell script to calculate the option ROM checksum with a fast AND
portable python version. Tested both with python 2.7 and 3.1.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
index f6b4027..57d8bd0 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -26,7 +26,7 @@ build-all: multiboot.bin linuxboot.bin kvmvapic.bin
$(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@," Building $(TARGET_DIR)$@")
%.bin: %.raw
- $(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/signrom.sh $< $@," Signing $(TARGET_DIR)$@")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/signrom.py $< $@," Signing $(TARGET_DIR)$@")
clean:
rm -f *.o *.d *.raw *.img *.bin *~
diff --git a/scripts/signrom.py b/scripts/signrom.py
new file mode 100644
index 0000000..f9c35cc
--- /dev/null
+++ b/scripts/signrom.py
@@ -0,0 +1,40 @@
+#
+# Option ROM signing utility
+#
+# Authors:
+# Jan Kiszka <jan.kiszka at siemens.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+import sys
+import struct
+
+if len(sys.argv) < 3:
+ print('usage: signrom.py input output')
+ sys.exit(1)
+
+fin = open(sys.argv[1], 'rb')
+fout = open(sys.argv[2], 'wb')
+
+fin.seek(2)
+size = ord(fin.read(1)) * 512 - 1
+
+fin.seek(0)
+data = fin.read(size)
+fout.write(data)
+
+checksum = 0
+for b in data:
+ # catch Python 2 vs. 3 differences
+ if isinstance(b, int):
+ checksum += b
+ else:
+ checksum += ord(b)
+checksum = (256 - checksum) % 256
+
+# Python 3 no longer allows chr(checksum)
+fout.write(struct.pack('B', checksum))
+
+fin.close()
+fout.close()
diff --git a/scripts/signrom.sh b/scripts/signrom.sh
deleted file mode 100755
index 9dc5c63..0000000
--- a/scripts/signrom.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/sh
-
-# Option ROM Signing utility
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
-# Copyright Novell Inc, 2009
-# Authors: Alexander Graf <agraf at suse.de>
-#
-# Syntax: signrom.sh <input> <output>
-
-# did we get proper arguments?
-test "$1" -a "$2" || exit 1
-
-sum=0
-
-# find out the file size
-x=`dd if="$1" bs=1 count=1 skip=2 2>/dev/null | od -t u1 -A n`
-#size=`expr $x \* 512 - 1`
-size=$(( $x * 512 - 1 ))
-
-# now get the checksum
-nums=`od -A n -t u1 -v -N $size "$1"`
-for i in ${nums}; do
- # add each byte's value to sum
- sum=`expr \( $sum + $i \) % 256`
-done
-
-sum=$(( (256 - $sum) % 256 ))
-sum_octal=$( printf "%o" $sum )
-
-# and write the output file
-cp "$1" "$2"
-printf "\\$sum_octal" | dd of="$2" bs=1 count=1 seek=$size conv=notrunc 2>/dev/null
commit e6f5d0be730a41bacb10edba19d1369ec2949486
Merge: 9444006... 55dd9ff...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sun Apr 15 19:56:06 2012 +0000
Merge branch 'w64' of git://qemu.weilnetz.de/qemu
* 'w64' of git://qemu.weilnetz.de/qemu:
w64: Fix time conversion for some versions of MinGW-w64
nbd: Fix compiler warning (w64)
disas: Replace 'unsigned long' by 'uintptr_t'
cpu-exec: Remove non-portable type cast and fix format string
target-mips: Fix type cast for w64 (uintptr_t)
w64: Fix type cast in os_host_main_loop_wait
w64: Fix data types in softmmu*.h
w64: Use uintptr_t in exec.c
softmmu: Use uintptr_t for physaddr and rename it
w64: Fix struct CPUTLBEntry
w64: Fix definition of setjmp
w32: Move defines for socket specific errors to qemu-os-win32.h
w64: Use larger alignment for section with generated code
w64: Fix data types in cpu-all.h, exec.c
w64: Fix type casts used in some macros in cpu-all.h
tcg/i386: Add support for w64 ABI
tcg/i386: Use GDB JIT debugging interface only for hosts with ELF
commit 9444006fa6ba1d5e4079ee534a7236124b66ea77
Author: Andreas Färber <afaerber at suse.de>
Date: Sat Apr 7 01:19:45 2012 +0200
target-alpha: QOM'ify CPU init
Move code from cpu_alpha_init() into a CPU initializer.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
index 315b0c1..62d2a66 100644
--- a/target-alpha/cpu.c
+++ b/target-alpha/cpu.c
@@ -1,6 +1,7 @@
/*
* QEMU Alpha CPU
*
+ * Copyright (c) 2007 Jocelyn Mayer
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This library is free software; you can redistribute it and/or
@@ -22,10 +23,29 @@
#include "qemu-common.h"
+static void alpha_cpu_initfn(Object *obj)
+{
+ AlphaCPU *cpu = ALPHA_CPU(obj);
+ CPUAlphaState *env = &cpu->env;
+
+ cpu_exec_init(env);
+ tlb_flush(env, 1);
+
+#if defined(CONFIG_USER_ONLY)
+ env->ps = PS_USER_MODE;
+ cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
+ | FPCR_UNFD | FPCR_INED | FPCR_DNOD
+ | FPCR_DYN_NORMAL));
+#endif
+ env->lock_addr = -1;
+ env->fen = 1;
+}
+
static const TypeInfo alpha_cpu_type_info = {
.name = TYPE_ALPHA_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(AlphaCPU),
+ .instance_init = alpha_cpu_initfn,
.abstract = false,
.class_size = sizeof(AlphaCPUClass),
};
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index f773e6c..12de6a3 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -3531,9 +3531,8 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
cpu = ALPHA_CPU(object_new(TYPE_ALPHA_CPU));
env = &cpu->env;
- cpu_exec_init(env);
+
alpha_translate_init();
- tlb_flush(env, 1);
/* Default to ev67; no reason not to emulate insns by default. */
implver = IMPLVER_21264;
@@ -3551,15 +3550,6 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
env->implver = implver;
env->amask = amask;
-#if defined (CONFIG_USER_ONLY)
- env->ps = PS_USER_MODE;
- cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
- | FPCR_UNFD | FPCR_INED | FPCR_DNOD
- | FPCR_DYN_NORMAL));
-#endif
- env->lock_addr = -1;
- env->fen = 1;
-
qemu_init_vcpu(env);
return env;
}
commit 25ebd80f1d0e4b8863968d56ccfe634ea577d365
Author: Andreas Färber <afaerber at suse.de>
Date: Fri Apr 6 19:46:48 2012 +0200
target-alpha: QOM'ify CPU
Embed CPUAlphaState as first member of AlphaCPU.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Richard Henderson <rth at twiddle.net>
diff --git a/Makefile.target b/Makefile.target
index 3ab791a..61dfe3b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -104,6 +104,7 @@ libobj-$(TARGET_SPARC64) += int64_helper.o
libobj-$(TARGET_UNICORE32) += cpu.o
libobj-$(TARGET_XTENSA) += cpu.o
libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
+libobj-$(TARGET_ALPHA) += cpu.o
libobj-y += disas.o
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h
new file mode 100644
index 0000000..6b4ca6d
--- /dev/null
+++ b/target-alpha/cpu-qom.h
@@ -0,0 +1,71 @@
+/*
+ * QEMU Alpha CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_ALPHA_CPU_QOM_H
+#define QEMU_ALPHA_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_ALPHA_CPU "alpha-cpu"
+
+#define ALPHA_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(AlphaCPUClass, (klass), TYPE_ALPHA_CPU)
+#define ALPHA_CPU(obj) \
+ OBJECT_CHECK(AlphaCPU, (obj), TYPE_ALPHA_CPU)
+#define ALPHA_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(AlphaCPUClass, (obj), TYPE_ALPHA_CPU)
+
+/**
+ * AlphaCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An Alpha CPU model.
+ */
+typedef struct AlphaCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} AlphaCPUClass;
+
+/**
+ * AlphaCPU:
+ * @env: #CPUAlphaState
+ *
+ * An Alpha CPU.
+ */
+typedef struct AlphaCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUAlphaState env;
+} AlphaCPU;
+
+static inline AlphaCPU *alpha_env_get_cpu(CPUAlphaState *env)
+{
+ return ALPHA_CPU(container_of(env, AlphaCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(alpha_env_get_cpu(e))
+
+
+#endif
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
new file mode 100644
index 0000000..315b0c1
--- /dev/null
+++ b/target-alpha/cpu.c
@@ -0,0 +1,38 @@
+/*
+ * QEMU Alpha CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+
+
+static const TypeInfo alpha_cpu_type_info = {
+ .name = TYPE_ALPHA_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(AlphaCPU),
+ .abstract = false,
+ .class_size = sizeof(AlphaCPUClass),
+};
+
+static void alpha_cpu_register_types(void)
+{
+ type_register_static(&alpha_cpu_type_info);
+}
+
+type_init(alpha_cpu_register_types)
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index fd578ce..99f9ee1 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -292,6 +292,7 @@ struct CPUAlphaState {
#define cpu_signal_handler cpu_alpha_signal_handler
#include "cpu-all.h"
+#include "cpu-qom.h"
enum {
FEATURE_ASN = 0x00000001,
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 1f4565d..f773e6c 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -3525,10 +3525,12 @@ static const struct cpu_def_t cpu_defs[] = {
CPUAlphaState * cpu_alpha_init (const char *cpu_model)
{
+ AlphaCPU *cpu;
CPUAlphaState *env;
int implver, amask, i, max;
- env = g_malloc0(sizeof(CPUAlphaState));
+ cpu = ALPHA_CPU(object_new(TYPE_ALPHA_CPU));
+ env = &cpu->env;
cpu_exec_init(env);
alpha_translate_init();
tlb_flush(env, 1);
commit 55dd9ffa70eb44f461b12c248c3df106ba8deca9
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 22:33:12 2012 +0200
w64: Fix time conversion for some versions of MinGW-w64
tb.time is a time value, but not necessarily of the same size as time_t:
while time_t is 64 bit for w64, tb.time still is 32 bit only.
Therefore we need en explicit conversion.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/savevm.c b/savevm.c
index 12fb209..2d18bab 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2106,7 +2106,8 @@ void do_savevm(Monitor *mon, const QDict *qdict)
}
} else {
#ifdef _WIN32
- ptm = localtime(&tb.time);
+ time_t t = tb.time;
+ ptm = localtime(&t);
strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm);
#else
/* cast below needed for OpenBSD where tv_sec is still 'long' */
commit 0fee8f342884e96b29d7df28475d0c485a317d54
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 22:30:16 2012 +0200
nbd: Fix compiler warning (w64)
Portable printing of dev_offset (data type off_t) needs a type cast.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/nbd.c b/nbd.c
index 567e94e..406e555 100644
--- a/nbd.c
+++ b/nbd.c
@@ -813,7 +813,7 @@ static void nbd_trip(void *opaque)
LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
", Offset: %" PRIu64 "\n",
request.from, request.len,
- (uint64_t)exp->size, exp->dev_offset);
+ (uint64_t)exp->size, (uint64_t)exp->dev_offset);
LOG("requested operation past EOF--bad client?");
goto invalid_request;
}
commit b0b0f1c964bb7643a6d4469ffd8157de84741d1f
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 15:44:35 2012 +0200
disas: Replace 'unsigned long' by 'uintptr_t'
This is needed for w64. It changes nothing for other hosts.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/disas.c b/disas.c
index 4f2c4e4..27071c3 100644
--- a/disas.c
+++ b/disas.c
@@ -268,7 +268,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size)
{
- unsigned long pc;
+ uintptr_t pc;
int count;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
@@ -276,7 +276,7 @@ void disas(FILE *out, void *code, unsigned long size)
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
disasm_info.buffer = code;
- disasm_info.buffer_vma = (unsigned long)code;
+ disasm_info.buffer_vma = (uintptr_t)code;
disasm_info.buffer_length = size;
#ifdef HOST_WORDS_BIGENDIAN
@@ -320,8 +320,8 @@ void disas(FILE *out, void *code, unsigned long size)
(long) code);
return;
#endif
- for (pc = (unsigned long)code; size > 0; pc += count, size -= count) {
- fprintf(out, "0x%08lx: ", pc);
+ for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
+ fprintf(out, "0x%08" PRIxPTR ": ", pc);
count = print_insn(pc, &disasm_info);
fprintf(out, "\n");
if (count < 0)
commit 3ba19255450666869ecfe764774c2371f989e68b
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 15:44:24 2012 +0200
cpu-exec: Remove non-portable type cast and fix format string
This change is needed for w64, but also changes the code for other hosts.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/cpu-exec.c b/cpu-exec.c
index d153f97..0344cd5 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -541,8 +541,8 @@ int cpu_exec(CPUArchState *env)
tb_invalidated_flag = 0;
}
#ifdef CONFIG_DEBUG_EXEC
- qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
- (long)tb->tc_ptr, tb->pc,
+ qemu_log_mask(CPU_LOG_EXEC, "Trace %p [" TARGET_FMT_lx "] %s\n",
+ tb->tc_ptr, tb->pc,
lookup_symbol(tb->pc));
#endif
/* see if we can patch the calling TB. When the TB
commit b69e48a84d83162efd4782472572783e99840cf5
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 15:43:09 2012 +0200
target-mips: Fix type cast for w64 (uintptr_t)
This changes nothing for other hosts.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index bca1d70..5627447 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -2275,7 +2275,7 @@ void helper_pmon (int function)
break;
case 158:
{
- unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
+ unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
printf("%s", fmt);
}
break;
commit 58b9630d7e2252d077b632c3a26d1aa334cf5fe6
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 20:42:34 2012 +0200
w64: Fix type cast in os_host_main_loop_wait
Casting a pointer to an integer must use (DWORD_PTR) instead of (DWORD).
This also matches the definition of 'fd' (gint for w32, gint64 for w64).
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/main-loop.c b/main-loop.c
index 1ebdc4b..4887c73 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -430,7 +430,7 @@ static int os_host_main_loop_wait(int timeout)
g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
for (i = 0; i < w->num; i++) {
- poll_fds[n_poll_fds + i].fd = (DWORD) w->events[i];
+ poll_fds[n_poll_fds + i].fd = (DWORD_PTR)w->events[i];
poll_fds[n_poll_fds + i].events = G_IO_IN;
}
commit b065927a02cbbaca032ed20d3039baca0914165c
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 14:14:51 2012 +0200
w64: Fix data types in softmmu*.h
w64 requires uintptr_t.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/softmmu_header.h b/softmmu_header.h
index 289dae2..cf1aa38 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -111,7 +111,7 @@ glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM
mmu_idx);
} else {
uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)hostaddr);
+ res = glue(glue(ld, USUFFIX), _raw)(hostaddr);
}
return res;
}
@@ -134,7 +134,7 @@ glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM
MMUSUFFIX)(ENV_VAR addr, mmu_idx);
} else {
uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)hostaddr);
+ res = glue(glue(lds, SUFFIX), _raw)(hostaddr);
}
return res;
}
@@ -161,7 +161,7 @@ glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr,
mmu_idx);
} else {
uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- glue(glue(st, SUFFIX), _raw)((uint8_t *)hostaddr, v);
+ glue(glue(st, SUFFIX), _raw)(hostaddr, v);
}
}
diff --git a/softmmu_template.h b/softmmu_template.h
index b285d78..b8bd700 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -112,7 +112,6 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM
int index;
target_ulong tlb_addr;
target_phys_addr_t ioaddr;
- unsigned long addend;
uintptr_t retaddr;
/* test if there is match for unaligned or IO access */
@@ -139,6 +138,7 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM
mmu_idx, retaddr);
} else {
/* unaligned/aligned access in the same page */
+ uintptr_t addend;
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
retaddr = GETPC();
@@ -146,7 +146,8 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM
}
#endif
addend = env->tlb_table[mmu_idx][index].addend;
- res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
+ res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t)
+ (addr + addend));
}
} else {
/* the page is not in the TLB : fill it */
@@ -171,7 +172,6 @@ glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM
DATA_TYPE res, res1, res2;
int index, shift;
target_phys_addr_t ioaddr;
- unsigned long addend;
target_ulong tlb_addr, addr1, addr2;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@@ -202,8 +202,9 @@ glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM
res = (DATA_TYPE)res;
} else {
/* unaligned/aligned access in the same page */
- addend = env->tlb_table[mmu_idx][index].addend;
- res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
+ uintptr_t addend = env->tlb_table[mmu_idx][index].addend;
+ res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t)
+ (addr + addend));
}
} else {
/* the page is not in the TLB : fill it */
@@ -258,7 +259,6 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM
int mmu_idx)
{
target_phys_addr_t ioaddr;
- unsigned long addend;
target_ulong tlb_addr;
uintptr_t retaddr;
int index;
@@ -284,6 +284,7 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM
mmu_idx, retaddr);
} else {
/* aligned/unaligned access in the same page */
+ uintptr_t addend;
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
retaddr = GETPC();
@@ -291,7 +292,8 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM
}
#endif
addend = env->tlb_table[mmu_idx][index].addend;
- glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
+ glue(glue(st, SUFFIX), _raw)((uint8_t *)(intptr_t)
+ (addr + addend), val);
}
} else {
/* the page is not in the TLB : fill it */
@@ -313,7 +315,6 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM
uintptr_t retaddr)
{
target_phys_addr_t ioaddr;
- unsigned long addend;
target_ulong tlb_addr;
int index, i;
@@ -345,8 +346,9 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM
}
} else {
/* aligned/unaligned access in the same page */
- addend = env->tlb_table[mmu_idx][index].addend;
- glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
+ uintptr_t addend = env->tlb_table[mmu_idx][index].addend;
+ glue(glue(st, SUFFIX), _raw)((uint8_t *)(intptr_t)
+ (addr + addend), val);
}
} else {
/* the page is not in the TLB : fill it */
commit 8efe0ca83eb9c5f996acc7a37d522da5c542ec79
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 15:42:19 2012 +0200
w64: Use uintptr_t in exec.c
Replace all type casts to 'long' or 'unsigned long' by 'intptr_t' or 'uintptr_t'.
For type casts which are only used to extract the lower bits of an address
or to modify those bits, signedness does not matter. There I always use 'uintptr_t'.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/exec.c b/exec.c
index 6d10595..77d6866 100644
--- a/exec.c
+++ b/exec.c
@@ -887,8 +887,8 @@ static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (tb1 == tb) {
*ptb = tb1->page_next[n1];
break;
@@ -908,8 +908,8 @@ static inline void tb_jmp_remove(TranslationBlock *tb, int n)
/* find tb(n) in circular list */
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
if (n1 == 2) {
@@ -929,7 +929,7 @@ static inline void tb_jmp_remove(TranslationBlock *tb, int n)
another TB */
static inline void tb_reset_jump(TranslationBlock *tb, int n)
{
- tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
+ tb_set_jmp_target(tb, n, (uintptr_t)(tb->tc_ptr + tb->tb_next_offset[n]));
}
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
@@ -974,16 +974,16 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
/* suppress any remaining jumps to this TB */
tb1 = tb->jmp_first;
for(;;) {
- n1 = (long)tb1 & 3;
+ n1 = (uintptr_t)tb1 & 3;
if (n1 == 2)
break;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
tb2 = tb1->jmp_next[n1];
tb_reset_jump(tb1, n1);
tb1->jmp_next[n1] = NULL;
tb1 = tb2;
}
- tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
+ tb->jmp_first = (TranslationBlock *)((uintptr_t)tb | 2); /* fail safe */
tb_phys_invalidate_count++;
}
@@ -1024,8 +1024,8 @@ static void build_page_bitmap(PageDesc *p)
tb = p->first_tb;
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
/* NOTE: this is subtle as a TB may span two physical pages */
if (n == 0) {
/* NOTE: tb_end may be after the end of the page, but
@@ -1069,7 +1069,8 @@ TranslationBlock *tb_gen_code(CPUArchState *env,
tb->flags = flags;
tb->cflags = cflags;
cpu_gen_code(env, tb, &code_gen_size);
- code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+ code_gen_ptr = (void *)(((uintptr_t)code_gen_ptr + code_gen_size +
+ CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
/* check next page if needed */
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
@@ -1117,8 +1118,8 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
/* XXX: see if in some cases it could be faster to invalidate all the code */
tb = p->first_tb;
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
tb_next = tb->page_next[n];
/* NOTE: this is subtle as a TB may span two physical pages */
if (n == 0) {
@@ -1201,7 +1202,8 @@ static inline void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
cpu_single_env->mem_io_vaddr, len,
cpu_single_env->eip,
- cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
+ cpu_single_env->eip +
+ (intptr_t)cpu_single_env->segs[R_CS].base);
}
#endif
p = page_find(start >> TARGET_PAGE_BITS);
@@ -1245,8 +1247,8 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr,
}
#endif
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
#ifdef TARGET_HAS_PRECISE_SMC
if (current_tb == tb &&
(current_tb->cflags & CF_COUNT_MASK) != 1) {
@@ -1294,7 +1296,7 @@ static inline void tb_alloc_page(TranslationBlock *tb,
#ifndef CONFIG_USER_ONLY
page_already_protected = p->first_tb != NULL;
#endif
- p->first_tb = (TranslationBlock *)((long)tb | n);
+ p->first_tb = (TranslationBlock *)((uintptr_t)tb | n);
invalidate_page_bitmap(p);
#if defined(TARGET_HAS_SMC) || 1
@@ -1361,7 +1363,7 @@ void tb_link_page(TranslationBlock *tb,
else
tb->page_addr[1] = -1;
- tb->jmp_first = (TranslationBlock *)((long)tb | 2);
+ tb->jmp_first = (TranslationBlock *)((uintptr_t)tb | 2);
tb->jmp_next[0] = NULL;
tb->jmp_next[1] = NULL;
@@ -1382,21 +1384,22 @@ void tb_link_page(TranslationBlock *tb,
TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
{
int m_min, m_max, m;
- unsigned long v;
+ uintptr_t v;
TranslationBlock *tb;
if (nb_tbs <= 0)
return NULL;
- if (tc_ptr < (unsigned long)code_gen_buffer ||
- tc_ptr >= (unsigned long)code_gen_ptr)
+ if (tc_ptr < (uintptr_t)code_gen_buffer ||
+ tc_ptr >= (uintptr_t)code_gen_ptr) {
return NULL;
+ }
/* binary search (cf Knuth) */
m_min = 0;
m_max = nb_tbs - 1;
while (m_min <= m_max) {
m = (m_min + m_max) >> 1;
tb = &tbs[m];
- v = (unsigned long)tb->tc_ptr;
+ v = (uintptr_t)tb->tc_ptr;
if (v == tc_ptr)
return tb;
else if (tc_ptr < v) {
@@ -1419,8 +1422,8 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
if (tb1 != NULL) {
/* find head of list */
for(;;) {
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == 2)
break;
tb1 = tb1->jmp_next[n1];
@@ -1432,8 +1435,8 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
ptb = &tb_next->jmp_first;
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
ptb = &tb1->jmp_next[n1];
@@ -2040,9 +2043,9 @@ static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe)
}
static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
- unsigned long start, unsigned long length)
+ uintptr_t start, uintptr_t length)
{
- unsigned long addr;
+ uintptr_t addr;
if (tlb_is_dirty_ram(tlb_entry)) {
addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
if ((addr - start) < length) {
@@ -2056,7 +2059,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
int dirty_flags)
{
CPUArchState *env;
- unsigned long length, start1;
+ uintptr_t length, start1;
int i;
start &= TARGET_PAGE_MASK;
@@ -2069,10 +2072,10 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
/* we modify the TLB cache so that the dirty bit will be set again
when accessing the range */
- start1 = (unsigned long)qemu_safe_ram_ptr(start);
+ start1 = (uintptr_t)qemu_safe_ram_ptr(start);
/* Check that we don't span multiple blocks - this breaks the
address comparisons below. */
- if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
+ if ((uintptr_t)qemu_safe_ram_ptr(end - 1) - start1
!= (end - 1) - start) {
abort();
}
@@ -2100,7 +2103,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
void *p;
if (tlb_is_dirty_ram(tlb_entry)) {
- p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+ p = (void *)(uintptr_t)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+ tlb_entry->addend);
ram_addr = qemu_ram_addr_from_host_nofail(p);
if (!cpu_physical_memory_is_dirty(ram_addr)) {
@@ -2190,7 +2193,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
unsigned int index;
target_ulong address;
target_ulong code_address;
- unsigned long addend;
+ uintptr_t addend;
CPUTLBEntry *te;
CPUWatchpoint *wp;
target_phys_addr_t iotlb;
@@ -2212,7 +2215,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
address |= TLB_MMIO;
}
if (is_ram_rom_romd(section)) {
- addend = (unsigned long)memory_region_get_ram_ptr(section->mr)
+ addend = (uintptr_t)memory_region_get_ram_ptr(section->mr)
+ section_addr(section, paddr);
} else {
addend = 0;
@@ -2302,7 +2305,7 @@ struct walk_memory_regions_data
{
walk_memory_regions_fn fn;
void *priv;
- unsigned long start;
+ uintptr_t start;
int prot;
};
@@ -2363,7 +2366,7 @@ static int walk_memory_regions_1(struct walk_memory_regions_data *data,
int walk_memory_regions(void *priv, walk_memory_regions_fn fn)
{
struct walk_memory_regions_data data;
- unsigned long i;
+ uintptr_t i;
data.fn = fn;
data.priv = priv;
@@ -2551,7 +2554,7 @@ int page_unprotect(target_ulong address, uintptr_t pc, void *puc)
}
static inline void tlb_set_dirty(CPUArchState *env,
- unsigned long addr, target_ulong vaddr)
+ uintptr_t addr, target_ulong vaddr)
{
}
#endif /* defined(CONFIG_USER_ONLY) */
commit 23ddbf08bfe3cf3e9d6993bd7918b6c4339ba2bb
Author: Stefan Weil <sw at weilnetz.de>
Date: Sun Apr 15 21:02:09 2012 +0200
softmmu: Use uintptr_t for physaddr and rename it
Variable physaddr is a host address which should be represented by
data type 'uintptr_t'.
This is needed for w64 and changes nothing for other hosts.
v2:
Rename physaddr -> hostaddr (suggested by Blue Swirl).
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/softmmu_header.h b/softmmu_header.h
index 6b72093..289dae2 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -99,7 +99,6 @@ glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM
int page_index;
RES_TYPE res;
target_ulong addr;
- unsigned long physaddr;
int mmu_idx;
addr = ptr;
@@ -111,8 +110,8 @@ glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM
addr,
mmu_idx);
} else {
- physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
+ uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+ res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)hostaddr);
}
return res;
}
@@ -124,7 +123,6 @@ glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM
{
int res, page_index;
target_ulong addr;
- unsigned long physaddr;
int mmu_idx;
addr = ptr;
@@ -135,8 +133,8 @@ glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM
res = (DATA_STYPE)glue(glue(glue(HELPER_PREFIX, ld), SUFFIX),
MMUSUFFIX)(ENV_VAR addr, mmu_idx);
} else {
- physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
+ uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+ res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)hostaddr);
}
return res;
}
@@ -152,7 +150,6 @@ glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr,
{
int page_index;
target_ulong addr;
- unsigned long physaddr;
int mmu_idx;
addr = ptr;
@@ -163,8 +160,8 @@ glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr,
glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_VAR addr, v,
mmu_idx);
} else {
- physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
+ uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+ glue(glue(st, SUFFIX), _raw)((uint8_t *)hostaddr, v);
}
}
commit 3b2992e42f8945f4bc6b9151f83dbf2bb5bcd538
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 20:29:36 2012 +0200
w64: Fix struct CPUTLBEntry
For w64, some entries need 'uintptr_t' instead of 'unsigned long'.
For other host systems, both data types are identical, so nothing changes.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/cpu-defs.h b/cpu-defs.h
index 88d8093..f49e950 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -98,12 +98,12 @@ typedef struct CPUTLBEntry {
target_ulong addr_code;
/* Addend to virtual address to get host address. IO accesses
use the corresponding iotlb value. */
- unsigned long addend;
+ uintptr_t addend;
/* padding to get a power of two size */
- uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) -
- (sizeof(target_ulong) * 3 +
- ((-sizeof(target_ulong) * 3) & (sizeof(unsigned long) - 1)) +
- sizeof(unsigned long))];
+ uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) -
+ (sizeof(target_ulong) * 3 +
+ ((-sizeof(target_ulong) * 3) & (sizeof(uintptr_t) - 1)) +
+ sizeof(uintptr_t))];
} CPUTLBEntry;
extern int CPUTLBEntry_wrong_size[sizeof(CPUTLBEntry) == (1 << CPU_TLB_ENTRY_BITS) ? 1 : -1];
commit 5cf6dd51abb252d25cb77d3b7a95a744bed1a69c
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 21:13:28 2012 +0200
w64: Fix definition of setjmp
The default definition of setjmp which is implemented in MinGW-w64
cannot be used with programs like QEMU which call longjmp from
code without structured exception handling (SEH).
This code therefore disables stack unwinding.
We could also implement SEH for QEMU's generated JIT code, but
that is much more difficult. Stack unwinding would also cost
execution time.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/qemu-os-win32.h b/qemu-os-win32.h
index b6533c0..753679b 100644
--- a/qemu-os-win32.h
+++ b/qemu-os-win32.h
@@ -56,6 +56,15 @@
# define EWOULDBLOCK WSAEWOULDBLOCK
#endif
+#if defined(_WIN64)
+/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
+ * If this parameter is NULL, longjump does no stack unwinding.
+ * That is what we need for QEMU. Passing the value of register rsp (default)
+ * lets longjmp try a stack unwinding which will crash with generated code. */
+# undef setjmp
+# define setjmp(env) _setjmp(env, NULL)
+#endif
+
/* Declaration of ffs() is missing in MinGW's strings.h. */
int ffs(int i);
commit acf126ba58425f11e74fbb9c1095224cb142fffa
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 21:13:15 2012 +0200
w32: Move defines for socket specific errors to qemu-os-win32.h
As those defines are only used for w32,
they should be in the header file for w32.
All files which include slirp.h or qemu_socket.h also
include qemu-os-win32.h.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/qemu-os-win32.h b/qemu-os-win32.h
index 8eda4bd..b6533c0 100644
--- a/qemu-os-win32.h
+++ b/qemu-os-win32.h
@@ -30,6 +30,32 @@
#include <winsock2.h>
#include "main-loop.h"
+/* Workaround for older versions of MinGW. */
+#ifndef ECONNREFUSED
+# define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef EINPROGRESS
+# define EINPROGRESS WSAEINPROGRESS
+#endif
+#ifndef EHOSTUNREACH
+# define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#ifndef EINTR
+# define EINTR WSAEINTR
+#endif
+#ifndef EINPROGRESS
+# define EINPROGRESS WSAEINPROGRESS
+#endif
+#ifndef ENETUNREACH
+# define ENETUNREACH WSAENETUNREACH
+#endif
+#ifndef ENOTCONN
+# define ENOTCONN WSAENOTCONN
+#endif
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+
/* Declaration of ffs() is missing in MinGW's strings.h. */
int ffs(int i);
diff --git a/qemu_socket.h b/qemu_socket.h
index 51ad210..a5d0a84 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -8,12 +8,6 @@
#include <ws2tcpip.h>
#define socket_error() WSAGetLastError()
-#undef EWOULDBLOCK
-#undef EINTR
-#undef EINPROGRESS
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define EINTR WSAEINTR
-#define EINPROGRESS WSAEINPROGRESS
int inet_aton(const char *cp, struct in_addr *ia);
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 46bfe46..f2c5eca 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -15,18 +15,6 @@ typedef char *caddr_t;
# include <sys/timeb.h>
# include <iphlpapi.h>
-# undef EWOULDBLOCK
-# undef EINPROGRESS
-# undef ENOTCONN
-# undef EHOSTUNREACH
-# undef ENETUNREACH
-# undef ECONNREFUSED
-# define EWOULDBLOCK WSAEWOULDBLOCK
-# define EINPROGRESS WSAEINPROGRESS
-# define ENOTCONN WSAENOTCONN
-# define EHOSTUNREACH WSAEHOSTUNREACH
-# define ENETUNREACH WSAENETUNREACH
-# define ECONNREFUSED WSAECONNREFUSED
#else
# define ioctlsocket ioctl
# define closesocket(s) close(s)
commit 6840981dfb76a1a1d2401efdb237ed5ddac8bf2f
Author: Stefan Weil <sw at weilnetz.de>
Date: Wed Apr 4 07:45:21 2012 +0200
w64: Use larger alignment for section with generated code
The MinGW-w64 compiler allows __attribute__((aligned (32)).
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/exec.c b/exec.c
index 3dda2ca..6d10595 100644
--- a/exec.c
+++ b/exec.c
@@ -93,8 +93,7 @@ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
#define code_gen_section \
__attribute__((__section__(".gen_code"))) \
__attribute__((aligned (32)))
-#elif defined(_WIN32)
-/* Maximum alignment for Win32 is 16. */
+#elif defined(_WIN32) && !defined(_WIN64)
#define code_gen_section \
__attribute__((aligned (16)))
#else
commit c6d506742fd997a29b611fda11f67c53d60dd5ef
Author: Stefan Weil <sw at weilnetz.de>
Date: Fri Mar 16 20:23:49 2012 +0100
w64: Fix data types in cpu-all.h, exec.c
w64 needs uintptr_t instead of unsigned long.
For other hosts, nothing changes.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/cpu-all.h b/cpu-all.h
index 58420be..f7d6867 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -299,10 +299,10 @@ extern unsigned long reserved_va;
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
-/* ??? These should be the larger of unsigned long and target_ulong. */
-extern unsigned long qemu_real_host_page_size;
-extern unsigned long qemu_host_page_size;
-extern unsigned long qemu_host_page_mask;
+/* ??? These should be the larger of uintptr_t and target_ulong. */
+extern uintptr_t qemu_real_host_page_size;
+extern uintptr_t qemu_host_page_size;
+extern uintptr_t qemu_host_page_mask;
#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask)
diff --git a/exec.c b/exec.c
index 68b8a6a..3dda2ca 100644
--- a/exec.c
+++ b/exec.c
@@ -177,9 +177,9 @@ typedef struct PageDesc {
#define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
-unsigned long qemu_real_host_page_size;
-unsigned long qemu_host_page_size;
-unsigned long qemu_host_page_mask;
+uintptr_t qemu_real_host_page_size;
+uintptr_t qemu_host_page_size;
+uintptr_t qemu_host_page_mask;
/* This is a multi-level map on the virtual address space.
The bottom level has pointers to PageDesc. */
commit 27b0dc16b4e50b59aeefff2bfa73cf2eb8c7a70d
Author: Stefan Weil <sw at weilnetz.de>
Date: Sun Apr 15 15:18:29 2012 +0200
w64: Fix type casts used in some macros in cpu-all.h
Instead of type casts to long, w64 needs type casts to intptr_t.
For other hosts, this changes nothing.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/cpu-all.h b/cpu-all.h
index 4512518..58420be 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -222,8 +222,8 @@ extern unsigned long reserved_va;
#else /* !CONFIG_USER_ONLY */
/* NOTE: we use double casts if pointers and target_ulong have
different sizes */
-#define saddr(x) (uint8_t *)(long)(x)
-#define laddr(x) (uint8_t *)(long)(x)
+#define saddr(x) (uint8_t *)(intptr_t)(x)
+#define laddr(x) (uint8_t *)(intptr_t)(x)
#endif
#define ldub_raw(p) ldub_p(laddr((p)))
commit 8d918718edcd6753aa12be96b71d1bd4fb6ed7cd
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 12 20:46:32 2012 +0200
tcg/i386: Add support for w64 ABI
w64 uses the registers rcx, rdx, r8 and r9 for function arguments,
so it needs a different declaration of tcg_target_call_iarg_regs.
rax, rcx, rdx, r8, r9, r10 and r11 may be changed by function calls.
rbx, rbp, rdi, rsi, r12, r13, r14 and r15 remain unchanged by function calls.
Reviewed-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 79545e3..da17bba 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -63,10 +63,15 @@ static const int tcg_target_reg_alloc_order[] = {
static const int tcg_target_call_iarg_regs[] = {
#if TCG_TARGET_REG_BITS == 64
+#if defined(_WIN64)
+ TCG_REG_RCX,
+ TCG_REG_RDX,
+#else
TCG_REG_RDI,
TCG_REG_RSI,
TCG_REG_RDX,
TCG_REG_RCX,
+#endif
TCG_REG_R8,
TCG_REG_R9,
#else
@@ -176,10 +181,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
ct->ct |= TCG_CT_REG;
if (TCG_TARGET_REG_BITS == 64) {
tcg_regset_set32(ct->u.regs, 0, 0xffff);
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI);
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[0]);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[1]);
#ifdef CONFIG_TCG_PASS_AREG0
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDX);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[2]);
#endif
} else {
tcg_regset_set32(ct->u.regs, 0, 0xff);
@@ -1300,9 +1305,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
use the ADDR32 prefix. For now, do nothing. */
if (offset != GUEST_BASE) {
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
- tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
- base = TCG_REG_RDI, offset = 0;
+ tcg_out_movi(s, TCG_TYPE_I64,
+ tcg_target_call_iarg_regs[0], GUEST_BASE);
+ tgen_arithr(s, ARITH_ADD + P_REXW,
+ tcg_target_call_iarg_regs[0], base);
+ base = tcg_target_call_iarg_regs[0];
+ offset = 0;
}
}
@@ -1434,8 +1442,8 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
#endif
#else
tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32),
- TCG_REG_RSI, data_reg);
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
+ tcg_target_call_iarg_regs[1], data_reg);
+ tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], mem_index);
stack_adjust = 0;
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
@@ -1474,9 +1482,12 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
use the ADDR32 prefix. For now, do nothing. */
if (offset != GUEST_BASE) {
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
- tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
- base = TCG_REG_RDI, offset = 0;
+ tcg_out_movi(s, TCG_TYPE_I64,
+ tcg_target_call_iarg_regs[0], GUEST_BASE);
+ tgen_arithr(s, ARITH_ADD + P_REXW,
+ tcg_target_call_iarg_regs[0], base);
+ base = tcg_target_call_iarg_regs[0];
+ offset = 0;
}
}
@@ -1977,6 +1988,10 @@ static int tcg_target_callee_save_regs[] = {
#if TCG_TARGET_REG_BITS == 64
TCG_REG_RBP,
TCG_REG_RBX,
+#if defined(_WIN64)
+ TCG_REG_RDI,
+ TCG_REG_RSI,
+#endif
TCG_REG_R12,
TCG_REG_R13,
TCG_REG_R14, /* Currently used for the global env. */
@@ -2064,8 +2079,10 @@ static void tcg_target_init(TCGContext *s)
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EDX);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_ECX);
if (TCG_TARGET_REG_BITS == 64) {
+#if !defined(_WIN64)
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RDI);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RSI);
+#endif
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R8);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R9);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R10);
commit c170cb66490aa20bfc8d2c2421481dd9195dbb8b
Author: Stefan Weil <sw at weilnetz.de>
Date: Fri Apr 6 08:06:41 2012 +0200
tcg/i386: Use GDB JIT debugging interface only for hosts with ELF
Not all i386 / x86_64 hosts use ELF.
Ask the compiler whether ELF is used.
On w64, gdb crashes when ELF_HOST_MACHINE is defined.
Cc: Blue Swirl <blauwirbel at gmail.com>
Acked-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Stefan Weil <sw at weilnetz.de>
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 871a7e7..79545e3 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -2102,7 +2102,9 @@ typedef struct {
DebugFrameFDE fde;
} DebugFrame;
-#if TCG_TARGET_REG_BITS == 64
+#if !defined(__ELF__)
+ /* Host machine without ELF. */
+#elif TCG_TARGET_REG_BITS == 64
#define ELF_HOST_MACHINE EM_X86_64
static DebugFrame debug_frame = {
.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
@@ -2156,6 +2158,7 @@ static DebugFrame debug_frame = {
};
#endif
+#if defined(ELF_HOST_MACHINE)
void tcg_register_jit(void *buf, size_t buf_size)
{
/* We're expecting a 2 byte uleb128 encoded value. */
@@ -2166,3 +2169,4 @@ void tcg_register_jit(void *buf, size_t buf_size)
tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
}
+#endif
commit 4d0365165dd831b9f5d305a1480447dd83810a55
Merge: b79b38e... c17491b...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sun Apr 15 18:39:55 2012 +0000
Merge branch 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf
* 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf:
pseries: Fix reset of VIO network device
pseries: Reset vscsi properly
pseries: Correctly use the device model reset hooks
pseries: Remove old hcalls hook stub
pseries: Remove old debug leftovers from spapr_vscsi
pseries: Fix RTAS based config access
target-ppc/machine.c: Drop unnecessary ifdefs
target-ppc: Init dcache and icache size for e500 user mode
target-ppc: Fix type casts for w64 (uintptr_t)
target-ppc: QOM'ify CPU reset
target-ppc: Start QOM'ifying CPU init
target-ppc: QOM'ify CPU
target-ppc: Add hooks for handling tcg and kvm limitations
target-ppc: Drop cpu_ppc_close()
pseries: Consolidate hack for RTAS display-character usage
pseries: Remove unused fields from VIOsPAPRBus structure
pseries: Implement RTAS system-reboot call
pseries: Fix bug with reset of VIO CRQs
pseries: Clean up hcall_dprintf() debugging messages
PPC: Fix TLB invalidation bug within the PPC interrupt handler.
commit c17491b63e198ac48d533f8a9d301d11c5880a36
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Thu Apr 12 12:44:15 2012 +1000
pseries: Fix reset of VIO network device
Currently, the PAPR VIO network device does not have a reset handler. This
means that after a hard reset, H_REGISTER_LOGICAL_LAN will return an error
when the new guest boot attempts to initialize the device.
This patch corrects this, adding a suitable reset hook.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 32dce17..e18d2eb 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -182,6 +182,15 @@ static NetClientInfo net_spapr_vlan_info = {
.receive = spapr_vlan_receive,
};
+static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
+{
+ VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev);
+
+ dev->buf_list = 0;
+ dev->rx_bufs = 0;
+ dev->isopen = 0;
+}
+
static int spapr_vlan_init(VIOsPAPRDevice *sdev)
{
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
@@ -335,9 +344,7 @@ static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr
return H_RESOURCE;
}
- dev->buf_list = 0;
- dev->rx_bufs = 0;
- dev->isopen = 0;
+ spapr_vlan_reset(sdev);
return H_SUCCESS;
}
@@ -484,6 +491,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data)
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_vlan_init;
+ k->reset = spapr_vlan_reset;
k->devnode = spapr_vlan_devnode;
k->dt_name = "l-lan";
k->dt_type = "network";
commit 3cabba609de07e06b3dacf4f30403f6e9e293f2c
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Thu Apr 12 12:44:14 2012 +1000
pseries: Reset vscsi properly
Currently the PAPR vscsi implementation does not properly clear its table
of request tags when the system is reset. This patch adds a reset hook
to do so.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 3530a38..538e0b7 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -893,16 +893,20 @@ static const struct SCSIBusInfo vscsi_scsi_info = {
.cancel = vscsi_request_cancelled
};
-static int spapr_vscsi_init(VIOsPAPRDevice *dev)
+static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
{
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
int i;
- /* Initialize qemu request tags */
memset(s->reqs, 0, sizeof(s->reqs));
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
s->reqs[i].qtag = i;
}
+}
+
+static int spapr_vscsi_init(VIOsPAPRDevice *dev)
+{
+ VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
dev->crq.SendFunc = vscsi_do_crq;
@@ -952,6 +956,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_vscsi_init;
+ k->reset = spapr_vscsi_reset;
k->devnode = spapr_vscsi_devnode;
k->dt_name = "v-scsi";
k->dt_type = "vscsi";
commit b1c7f725a3bc5fec87912e907066edd6b80b878c
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Thu Apr 12 12:44:13 2012 +1000
pseries: Correctly use the device model reset hooks
Recently we added code to properly clean away VIO CRQs on reset However,
this directly uses qemu_register, rather than the existing device model
reset callbacks. This patch cleans this up by adding proper use of the
reset hook to the VIO bus model. The existing CRQ reset code is converted
to the new method.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 0bf2c31..fccf48b 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -648,13 +648,18 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
return 0;
}
-static void spapr_vio_busdev_reset(void *opaque)
+static void spapr_vio_busdev_reset(DeviceState *qdev)
{
- VIOsPAPRDevice *dev = (VIOsPAPRDevice *)opaque;
+ VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
+ VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
if (dev->crq.qsize) {
free_crq(dev);
}
+
+ if (pc->reset) {
+ pc->reset(dev);
+ }
}
static int spapr_vio_busdev_init(DeviceState *qdev)
@@ -685,8 +690,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
rtce_init(dev);
- qemu_register_reset(spapr_vio_busdev_reset, dev);
-
return pc->init(dev);
}
@@ -776,6 +779,7 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->init = spapr_vio_busdev_init;
+ k->reset = spapr_vio_busdev_reset;
k->bus_info = &spapr_vio_bus_info;
}
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 626d04f..10ab359 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -64,6 +64,7 @@ typedef struct VIOsPAPRDeviceClass {
const char *dt_name, *dt_type, *dt_compatible;
target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev);
+ void (*reset)(VIOsPAPRDevice *dev);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
} VIOsPAPRDeviceClass;
commit 91067bf8689ad4a4489a5080812619a9eb932716
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Thu Apr 12 12:44:12 2012 +1000
pseries: Remove old hcalls hook stub
Some time ago we removed all use of the 'hcalls' callback in the pseries
VIO code, which was used to workaround an ordering problem which has since
been solved properly. However, the function pointer for the hook remains.
This patch cleans it away.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index fd29c5e..626d04f 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -64,7 +64,6 @@ typedef struct VIOsPAPRDeviceClass {
const char *dt_name, *dt_type, *dt_compatible;
target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev);
- void (*hcalls)(VIOsPAPRBus *bus);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
} VIOsPAPRDeviceClass;
commit e2d9154dfab73c36ead3cd368e7bc702dfb2ab68
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Thu Apr 12 12:44:11 2012 +1000
pseries: Remove old debug leftovers from spapr_vscsi
The PAPR VSCSI emulation contains a few lines of code which were once used
for debug but now do nothing at all. This patch removes them.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 2167017..3530a38 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -99,10 +99,6 @@ typedef struct {
vscsi_req reqs[VSCSI_REQ_LIMIT];
} VSCSIState;
-/* XXX Debug only */
-static VSCSIState *dbg_vscsi_state;
-
-
static struct vscsi_req *vscsi_get_req(VSCSIState *s)
{
vscsi_req *req;
@@ -902,8 +898,6 @@ static int spapr_vscsi_init(VIOsPAPRDevice *dev)
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
int i;
- dbg_vscsi_state = s;
-
/* Initialize qemu request tags */
memset(s->reqs, 0, sizeof(s->reqs));
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
commit 92615a5ab96cd2b4981e2aaef40bece6cd7553b6
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Mon Apr 2 14:17:35 2012 +1000
pseries: Fix RTAS based config access
On the pseries platform, access to PCI config space is via RTAS calls(
which go to the hypervisor) rather than MMIO. This means we don't use
the same code path as nearly everyone else which goes through pci_host.c
and we're missing some of the parameter checking along the way.
We do have some parameter checking in the RTAS calls, but it's not enough.
It checks for overruns, but does not check for unaligned accesses,
oversized accesses (which means the guest could trigger an assertion
failure from pci_host_config_{read,write}_common(). Worse it doesn't do
the basic checking for the number of RTAS arguments and results before
accessing them.
This patch fixes these bugs.
Cc: Michael S. Tsirkin <mst at redhat.com>
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
[AF: Fix typos spotted by mst]
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index e7ef551..a564c00 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -57,26 +57,38 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr,
static uint32_t rtas_pci_cfgaddr(uint32_t arg)
{
+ /* This handles the encoding of extended config space addresses */
return ((arg >> 20) & 0xf00) | (arg & 0xff);
}
-static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
- uint32_t limit, uint32_t len)
+static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,
+ uint32_t addr, uint32_t size,
+ target_ulong rets)
{
- if ((addr + len) <= limit) {
- return pci_host_config_read_common(pci_dev, addr, limit, len);
- } else {
- return ~0x0;
+ PCIDevice *pci_dev;
+ uint32_t val;
+
+ if ((size != 1) && (size != 2) && (size != 4)) {
+ /* access must be 1, 2 or 4 bytes */
+ rtas_st(rets, 0, -1);
+ return;
}
-}
-static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
- uint32_t limit, uint32_t val,
- uint32_t len)
-{
- if ((addr + len) <= limit) {
- pci_host_config_write_common(pci_dev, addr, limit, val, len);
+ pci_dev = find_dev(spapr, buid, addr);
+ addr = rtas_pci_cfgaddr(addr);
+
+ if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
+ /* Access must be to a valid device, within bounds and
+ * naturally aligned */
+ rtas_st(rets, 0, -1);
+ return;
}
+
+ val = pci_host_config_read_common(pci_dev, addr,
+ pci_config_size(pci_dev), size);
+
+ rtas_st(rets, 0, 0);
+ rtas_st(rets, 1, val);
}
static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
@@ -84,19 +96,19 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- uint32_t val, size, addr;
- uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
- PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
+ uint64_t buid;
+ uint32_t size, addr;
- if (!dev) {
+ if ((nargs != 4) || (nret != 2)) {
rtas_st(rets, 0, -1);
return;
}
+
+ buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
size = rtas_ld(args, 3);
- addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
- val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
- rtas_st(rets, 0, 0);
- rtas_st(rets, 1, val);
+ addr = rtas_ld(args, 0);
+
+ finish_read_pci_config(spapr, buid, addr, size, rets);
}
static void rtas_read_pci_config(sPAPREnvironment *spapr,
@@ -104,18 +116,45 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- uint32_t val, size, addr;
- PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
+ uint32_t size, addr;
- if (!dev) {
+ if ((nargs != 2) || (nret != 2)) {
rtas_st(rets, 0, -1);
return;
}
+
size = rtas_ld(args, 1);
- addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
- val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
+ addr = rtas_ld(args, 0);
+
+ finish_read_pci_config(spapr, 0, addr, size, rets);
+}
+
+static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid,
+ uint32_t addr, uint32_t size,
+ uint32_t val, target_ulong rets)
+{
+ PCIDevice *pci_dev;
+
+ if ((size != 1) && (size != 2) && (size != 4)) {
+ /* access must be 1, 2 or 4 bytes */
+ rtas_st(rets, 0, -1);
+ return;
+ }
+
+ pci_dev = find_dev(spapr, buid, addr);
+ addr = rtas_pci_cfgaddr(addr);
+
+ if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
+ /* Access must be to a valid device, within bounds and
+ * naturally aligned */
+ rtas_st(rets, 0, -1);
+ return;
+ }
+
+ pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev),
+ val, size);
+
rtas_st(rets, 0, 0);
- rtas_st(rets, 1, val);
}
static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
@@ -123,19 +162,20 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
target_ulong args,
uint32_t nret, target_ulong rets)
{
+ uint64_t buid;
uint32_t val, size, addr;
- uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
- PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
- if (!dev) {
+ if ((nargs != 5) || (nret != 1)) {
rtas_st(rets, 0, -1);
return;
}
+
+ buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
val = rtas_ld(args, 4);
size = rtas_ld(args, 3);
- addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
- rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
- rtas_st(rets, 0, 0);
+ addr = rtas_ld(args, 0);
+
+ finish_write_pci_config(spapr, buid, addr, size, val, rets);
}
static void rtas_write_pci_config(sPAPREnvironment *spapr,
@@ -144,17 +184,18 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
uint32_t val, size, addr;
- PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
- if (!dev) {
+ if ((nargs != 3) || (nret != 1)) {
rtas_st(rets, 0, -1);
return;
}
+
+
val = rtas_ld(args, 2);
size = rtas_ld(args, 1);
- addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
- rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
- rtas_st(rets, 0, 0);
+ addr = rtas_ld(args, 0);
+
+ finish_write_pci_config(spapr, 0, addr, size, val, rets);
}
static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
commit b79b38e4b3199984a6ad0ead5be2431c8e804eaa
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Sun Apr 15 19:12:18 2012 +0400
target-xtensa: add license to core-fsf.c
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-xtensa/core-fsf.c b/target-xtensa/core-fsf.c
index c11d970..e36b0de 100644
--- a/target-xtensa/core-fsf.c
+++ b/target-xtensa/core-fsf.c
@@ -1,3 +1,30 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
#include "cpu.h"
#include "exec-all.h"
#include "gdbstub.h"
commit fbaa9fb5cbfad74e7df1230acf4b7f5cb4a9f089
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Sun Apr 15 19:12:17 2012 +0400
target-xtensa: add license to core-dc232b.c
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-xtensa/core-dc232b.c b/target-xtensa/core-dc232b.c
index 7c03835..804fdef 100644
--- a/target-xtensa/core-dc232b.c
+++ b/target-xtensa/core-dc232b.c
@@ -1,3 +1,30 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
#include "cpu.h"
#include "exec-all.h"
#include "gdbstub.h"
commit 176ac95ed19f7728985d3d904671732a54eb42e7
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Sun Apr 15 19:12:16 2012 +0400
target-xtensa: add dc233c core
This is Diamond 233L Standard Core Rev.C (LE), implemented through
linux/gdb overlay.
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile.target b/Makefile.target
index 65fb8f0..3ab791a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -416,6 +416,7 @@ obj-xtensa-y += xtensa_sim.o
obj-xtensa-y += xtensa_lx60.o
obj-xtensa-y += xtensa-semi.o
obj-xtensa-y += core-dc232b.o
+obj-xtensa-y += core-dc233c.o
obj-xtensa-y += core-fsf.o
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/target-xtensa/core-dc233c.c b/target-xtensa/core-dc233c.c
new file mode 100644
index 0000000..d643f41
--- /dev/null
+++ b/target-xtensa/core-dc233c.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+
+#include "core-dc233c/core-isa.h"
+#include "overlay_tool.h"
+
+static const XtensaConfig dc233c = {
+ .name = "dc233c",
+ .options = XTENSA_OPTIONS,
+ .gdb_regmap = {
+ .num_regs = 121,
+ .num_core_regs = 52,
+ .reg = {
+#include "core-dc233c/gdb-config.c"
+ }
+ },
+ .nareg = XCHAL_NUM_AREGS,
+ .ndepc = 1,
+ EXCEPTIONS_SECTION,
+ INTERRUPTS_SECTION,
+ TLB_SECTION,
+ .clock_freq_khz = 10000,
+};
+
+REGISTER_CORE(dc233c)
diff --git a/target-xtensa/core-dc233c/core-isa.h b/target-xtensa/core-dc233c/core-isa.h
new file mode 100644
index 0000000..e82c3cb
--- /dev/null
+++ b/target-xtensa/core-dc233c/core-isa.h
@@ -0,0 +1,474 @@
+/*
+ * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa
+ * processor CORE configuration
+ *
+ * See <xtensa/config/core.h>, which includes this file, for more details.
+ */
+
+/* Xtensa processor core configuration information.
+
+ Copyright (c) 1999-2010 Tensilica Inc.
+
+ 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 _XTENSA_CORE_CONFIGURATION_H
+#define _XTENSA_CORE_CONFIGURATION_H
+
+
+/****************************************************************************
+ Parameters Useful for Any Code, USER or PRIVILEGED
+ ****************************************************************************/
+
+/*
+ * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
+ * configured, and a value of 0 otherwise. These macros are always defined.
+ */
+
+
+/*----------------------------------------------------------------------
+ ISA
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */
+#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */
+#define XCHAL_NUM_AREGS 32 /* num of physical addr regs */
+#define XCHAL_NUM_AREGS_LOG2 5 /* log2(XCHAL_NUM_AREGS) */
+#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */
+#define XCHAL_HAVE_DEBUG 1 /* debug option */
+#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */
+#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */
+#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */
+#define XCHAL_HAVE_MINMAX 1 /* MIN/MAX instructions */
+#define XCHAL_HAVE_SEXT 1 /* SEXT instruction */
+#define XCHAL_HAVE_CLAMPS 1 /* CLAMPS instruction */
+#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */
+#define XCHAL_HAVE_MUL32 1 /* MULL instruction */
+#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */
+#define XCHAL_HAVE_DIV32 1 /* QUOS/QUOU/REMS/REMU instructions */
+#define XCHAL_HAVE_L32R 1 /* L32R instruction */
+#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */
+#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */
+#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */
+#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */
+#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */
+#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */
+#define XCHAL_HAVE_ABS 1 /* ABS instruction */
+/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */
+/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */
+#define XCHAL_HAVE_RELEASE_SYNC 1 /* L32AI/S32RI instructions */
+#define XCHAL_HAVE_S32C1I 1 /* S32C1I instruction */
+#define XCHAL_HAVE_SPECULATION 0 /* speculation */
+#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */
+#define XCHAL_NUM_CONTEXTS 1 /* */
+#define XCHAL_NUM_MISC_REGS 2 /* num of scratch regs (0..4) */
+#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */
+#define XCHAL_HAVE_PRID 1 /* processor ID register */
+#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */
+#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */
+#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */
+#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */
+#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */
+#define XCHAL_HAVE_CP 1 /* CPENABLE reg (coprocessor) */
+#define XCHAL_CP_MAXCFG 8 /* max allowed cp id plus one */
+#define XCHAL_HAVE_MAC16 1 /* MAC16 package */
+#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */
+#define XCHAL_HAVE_FP 0 /* floating point pkg */
+#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */
+#define XCHAL_HAVE_DFP_accel 0 /* double precision FP acceleration pkg */
+#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */
+#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */
+#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */
+#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */
+#define XCHAL_HAVE_HIFI2EP 0 /* HiFi2EP */
+#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */
+#define XCHAL_HAVE_BBE16 0 /* ConnX BBE16 pkg */
+#define XCHAL_HAVE_BBE16_RSQRT 0 /* BBE16 & vector recip sqrt */
+#define XCHAL_HAVE_BBE16_VECDIV 0 /* BBE16 & vector divide */
+#define XCHAL_HAVE_BBE16_DESPREAD 0 /* BBE16 & despread */
+#define XCHAL_HAVE_BSP3 0 /* ConnX BSP3 pkg */
+#define XCHAL_HAVE_SSP16 0 /* ConnX SSP16 pkg */
+#define XCHAL_HAVE_SSP16_VITERBI 0 /* SSP16 & viterbi */
+#define XCHAL_HAVE_TURBO16 0 /* ConnX Turbo16 pkg */
+#define XCHAL_HAVE_BBP16 0 /* ConnX BBP16 pkg */
+
+
+/*----------------------------------------------------------------------
+ MISC
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES 8 /* size of write buffer */
+#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */
+#define XCHAL_DATA_WIDTH 4 /* data width in bytes */
+/* In T1050, applies to selected core load and store instructions (see ISA): */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/
+#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */
+#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/
+
+#define XCHAL_SW_VERSION 900001 /* sw version of this header */
+
+#define XCHAL_CORE_ID "dc233c" /* alphanum core name
+(CoreID) set in the Xtensa
+Processor Generator */
+
+#define XCHAL_CORE_DESCRIPTION "dc233c"
+#define XCHAL_BUILD_UNIQUE_ID 0x00004B21 /* 22-bit sw build ID */
+
+/*
+ * These definitions describe the hardware targeted by this software.
+ */
+#define XCHAL_HW_CONFIGID0 0xC56707FE /* ConfigID hi 32 bits*/
+#define XCHAL_HW_CONFIGID1 0x14404B21 /* ConfigID lo 32 bits*/
+#define XCHAL_HW_VERSION_NAME "LX4.0.1" /* full version name */
+#define XCHAL_HW_VERSION_MAJOR 2400 /* major ver# of targeted hw */
+#define XCHAL_HW_VERSION_MINOR 1 /* minor ver# of targeted hw */
+#define XCHAL_HW_VERSION 240001 /* major*100+minor */
+#define XCHAL_HW_REL_LX4 1
+#define XCHAL_HW_REL_LX4_0 1
+#define XCHAL_HW_REL_LX4_0_1 1
+#define XCHAL_HW_CONFIGID_RELIABLE 1
+/* If software targets a *range* of hardware versions, these are the bounds: */
+#define XCHAL_HW_MIN_VERSION_MAJOR 2400 /* major v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION_MINOR 1 /* minor v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION 240001 /* earliest targeted hw */
+#define XCHAL_HW_MAX_VERSION_MAJOR 2400 /* major v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MINOR 1 /* minor v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION 240001 /* latest targeted hw */
+
+
+/*----------------------------------------------------------------------
+ CACHE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_ICACHE_LINESIZE 32 /* I-cache line size in bytes */
+#define XCHAL_DCACHE_LINESIZE 32 /* D-cache line size in bytes */
+#define XCHAL_ICACHE_LINEWIDTH 5 /* log2(I line size in bytes) */
+#define XCHAL_DCACHE_LINEWIDTH 5 /* log2(D line size in bytes) */
+
+#define XCHAL_ICACHE_SIZE 16384 /* I-cache size in bytes or 0 */
+#define XCHAL_DCACHE_SIZE 16384 /* D-cache size in bytes or 0 */
+
+#define XCHAL_DCACHE_IS_WRITEBACK 1 /* writeback feature */
+#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */
+
+#define XCHAL_HAVE_PREFETCH 0 /* PREFCTL register */
+
+
+
+
+/****************************************************************************
+ Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
+ ****************************************************************************/
+
+
+#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
+
+/*----------------------------------------------------------------------
+ CACHE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */
+
+/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */
+
+/* Number of cache sets in log2(lines per way): */
+#define XCHAL_ICACHE_SETWIDTH 7
+#define XCHAL_DCACHE_SETWIDTH 7
+
+/* Cache set associativity (number of ways): */
+#define XCHAL_ICACHE_WAYS 4
+#define XCHAL_DCACHE_WAYS 4
+
+/* Cache features: */
+#define XCHAL_ICACHE_LINE_LOCKABLE 1
+#define XCHAL_DCACHE_LINE_LOCKABLE 1
+#define XCHAL_ICACHE_ECC_PARITY 0
+#define XCHAL_DCACHE_ECC_PARITY 0
+
+/* Cache access size in bytes (affects operation of SICW instruction): */
+#define XCHAL_ICACHE_ACCESS_SIZE 4
+#define XCHAL_DCACHE_ACCESS_SIZE 4
+
+/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */
+#define XCHAL_CA_BITS 4
+
+
+/*----------------------------------------------------------------------
+ INTERNAL I/D RAM/ROMs and XLMI
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */
+#define XCHAL_NUM_INSTRAM 0 /* number of core instr. RAMs */
+#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */
+#define XCHAL_NUM_DATARAM 0 /* number of core data RAMs */
+#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/
+#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports */
+
+#define XCHAL_HAVE_IMEM_LOADSTORE 1 /* can load/store to IROM/IRAM*/
+
+
+/*----------------------------------------------------------------------
+ INTERRUPTS and TIMERS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */
+#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */
+#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */
+#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */
+#define XCHAL_NUM_INTERRUPTS 22 /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */
+#define XCHAL_NUM_EXTINTERRUPTS 17 /* num of external interrupts */
+#define XCHAL_NUM_INTLEVELS 6 /* number of interrupt levels
+(not including level zero) */
+#define XCHAL_EXCM_LEVEL 3 /* level masked by PS.EXCM */
+/* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
+
+/* Masks of interrupts at each interrupt level: */
+#define XCHAL_INTLEVEL1_MASK 0x001F80FF
+#define XCHAL_INTLEVEL2_MASK 0x00000100
+#define XCHAL_INTLEVEL3_MASK 0x00200E00
+#define XCHAL_INTLEVEL4_MASK 0x00001000
+#define XCHAL_INTLEVEL5_MASK 0x00002000
+#define XCHAL_INTLEVEL6_MASK 0x00000000
+#define XCHAL_INTLEVEL7_MASK 0x00004000
+
+/* Masks of interrupts at each range 1..n of interrupt levels: */
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x001F80FF
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x001F81FF
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x003F8FFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x003F9FFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x003FBFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x003FBFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x003FFFFF
+
+/* Level of each interrupt: */
+#define XCHAL_INT0_LEVEL 1
+#define XCHAL_INT1_LEVEL 1
+#define XCHAL_INT2_LEVEL 1
+#define XCHAL_INT3_LEVEL 1
+#define XCHAL_INT4_LEVEL 1
+#define XCHAL_INT5_LEVEL 1
+#define XCHAL_INT6_LEVEL 1
+#define XCHAL_INT7_LEVEL 1
+#define XCHAL_INT8_LEVEL 2
+#define XCHAL_INT9_LEVEL 3
+#define XCHAL_INT10_LEVEL 3
+#define XCHAL_INT11_LEVEL 3
+#define XCHAL_INT12_LEVEL 4
+#define XCHAL_INT13_LEVEL 5
+#define XCHAL_INT14_LEVEL 7
+#define XCHAL_INT15_LEVEL 1
+#define XCHAL_INT16_LEVEL 1
+#define XCHAL_INT17_LEVEL 1
+#define XCHAL_INT18_LEVEL 1
+#define XCHAL_INT19_LEVEL 1
+#define XCHAL_INT20_LEVEL 1
+#define XCHAL_INT21_LEVEL 3
+#define XCHAL_DEBUGLEVEL 6 /* debug interrupt level */
+#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */
+#define XCHAL_NMILEVEL 7 /* NMI "level" (for use with
+EXCSAVE/EPS/EPC_n, RFI n) */
+
+/* Type of each interrupt: */
+#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT10_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT11_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT13_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI
+#define XCHAL_INT15_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT16_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT17_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT18_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT19_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT20_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT21_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+
+/* Masks of interrupts for each type of interrupt: */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFC00000
+#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000880
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x003F8000
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000133F
+#define XCHAL_INTTYPE_MASK_TIMER 0x00002440
+#define XCHAL_INTTYPE_MASK_NMI 0x00004000
+#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000
+
+/* Interrupt numbers assigned to specific interrupt sources: */
+#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */
+#define XCHAL_TIMER1_INTERRUPT 10 /* CCOMPARE1 */
+#define XCHAL_TIMER2_INTERRUPT 13 /* CCOMPARE2 */
+#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
+#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */
+
+/* Interrupt numbers for levels at which only one interrupt is configured: */
+#define XCHAL_INTLEVEL2_NUM 8
+#define XCHAL_INTLEVEL4_NUM 12
+#define XCHAL_INTLEVEL5_NUM 13
+#define XCHAL_INTLEVEL7_NUM 14
+/* (There are many interrupts each at level(s) 1, 3.) */
+
+
+/*
+ * External interrupt vectors/levels.
+ * These macros describe how Xtensa processor interrupt numbers
+ * (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ * map to external BInterrupt<n> pins, for those interrupts
+ * configured as external (level-triggered, edge-triggered, or NMI).
+ * See the Xtensa processor databook for more details.
+ */
+
+/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */
+#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */
+#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */
+#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM 8 /* (intlevel 2) */
+#define XCHAL_EXTINT7_NUM 9 /* (intlevel 3) */
+#define XCHAL_EXTINT8_NUM 12 /* (intlevel 4) */
+#define XCHAL_EXTINT9_NUM 14 /* (intlevel 7) */
+#define XCHAL_EXTINT10_NUM 15 /* (intlevel 1) */
+#define XCHAL_EXTINT11_NUM 16 /* (intlevel 1) */
+#define XCHAL_EXTINT12_NUM 17 /* (intlevel 1) */
+#define XCHAL_EXTINT13_NUM 18 /* (intlevel 1) */
+#define XCHAL_EXTINT14_NUM 19 /* (intlevel 1) */
+#define XCHAL_EXTINT15_NUM 20 /* (intlevel 1) */
+#define XCHAL_EXTINT16_NUM 21 /* (intlevel 3) */
+
+
+/*----------------------------------------------------------------------
+ EXCEPTIONS and VECTORS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture
+number: 1 == XEA1 (old)
+2 == XEA2 (new)
+0 == XEAX (extern) or TX */
+#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */
+#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */
+#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */
+#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */
+#define XCHAL_HAVE_HALT 0 /* halt architecture option */
+#define XCHAL_HAVE_BOOTLOADER 0 /* boot loader (for TX) */
+#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */
+#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */
+#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */
+#define XCHAL_VECBASE_RESET_VADDR 0x00002000 /* VECBASE reset value */
+#define XCHAL_VECBASE_RESET_PADDR 0x00002000
+#define XCHAL_RESET_VECBASE_OVERLAP 0
+
+#define XCHAL_RESET_VECTOR0_VADDR 0xFE000000
+#define XCHAL_RESET_VECTOR0_PADDR 0xFE000000
+#define XCHAL_RESET_VECTOR1_VADDR 0x00001000
+#define XCHAL_RESET_VECTOR1_PADDR 0x00001000
+#define XCHAL_RESET_VECTOR_VADDR 0xFE000000
+#define XCHAL_RESET_VECTOR_PADDR 0xFE000000
+#define XCHAL_USER_VECOFS 0x00000340
+#define XCHAL_USER_VECTOR_VADDR 0x00002340
+#define XCHAL_USER_VECTOR_PADDR 0x00002340
+#define XCHAL_KERNEL_VECOFS 0x00000300
+#define XCHAL_KERNEL_VECTOR_VADDR 0x00002300
+#define XCHAL_KERNEL_VECTOR_PADDR 0x00002300
+#define XCHAL_DOUBLEEXC_VECOFS 0x000003C0
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x000023C0
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x000023C0
+#define XCHAL_WINDOW_OF4_VECOFS 0x00000000
+#define XCHAL_WINDOW_UF4_VECOFS 0x00000040
+#define XCHAL_WINDOW_OF8_VECOFS 0x00000080
+#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0
+#define XCHAL_WINDOW_OF12_VECOFS 0x00000100
+#define XCHAL_WINDOW_UF12_VECOFS 0x00000140
+#define XCHAL_WINDOW_VECTORS_VADDR 0x00002000
+#define XCHAL_WINDOW_VECTORS_PADDR 0x00002000
+#define XCHAL_INTLEVEL2_VECOFS 0x00000180
+#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x00002180
+#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x00002180
+#define XCHAL_INTLEVEL3_VECOFS 0x000001C0
+#define XCHAL_INTLEVEL3_VECTOR_VADDR 0x000021C0
+#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x000021C0
+#define XCHAL_INTLEVEL4_VECOFS 0x00000200
+#define XCHAL_INTLEVEL4_VECTOR_VADDR 0x00002200
+#define XCHAL_INTLEVEL4_VECTOR_PADDR 0x00002200
+#define XCHAL_INTLEVEL5_VECOFS 0x00000240
+#define XCHAL_INTLEVEL5_VECTOR_VADDR 0x00002240
+#define XCHAL_INTLEVEL5_VECTOR_PADDR 0x00002240
+#define XCHAL_INTLEVEL6_VECOFS 0x00000280
+#define XCHAL_INTLEVEL6_VECTOR_VADDR 0x00002280
+#define XCHAL_INTLEVEL6_VECTOR_PADDR 0x00002280
+#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL6_VECOFS
+#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL6_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL6_VECTOR_PADDR
+#define XCHAL_NMI_VECOFS 0x000002C0
+#define XCHAL_NMI_VECTOR_VADDR 0x000022C0
+#define XCHAL_NMI_VECTOR_PADDR 0x000022C0
+#define XCHAL_INTLEVEL7_VECOFS XCHAL_NMI_VECOFS
+#define XCHAL_INTLEVEL7_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR
+#define XCHAL_INTLEVEL7_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR
+
+
+/*----------------------------------------------------------------------
+ DEBUG
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */
+#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */
+#define XCHAL_HAVE_OCD_DIR_ARRAY 1 /* faster OCD option */
+
+
+/*----------------------------------------------------------------------
+ MMU
+ ----------------------------------------------------------------------*/
+
+/* See core-matmap.h header file for more details. */
+
+#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */
+#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */
+#define XCHAL_SPANNING_WAY 6 /* TLB spanning way number */
+#define XCHAL_HAVE_IDENTITY_MAP 0 /* vaddr == paddr always */
+#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */
+#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* region protection */
+#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */
+#define XCHAL_HAVE_PTP_MMU 1 /* full MMU (with page table
+[autorefill] and protection)
+usable for an MMU-based OS */
+/* If none of the above last 4 are set, it's a custom TLB configuration. */
+#define XCHAL_ITLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */
+#define XCHAL_DTLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */
+
+#define XCHAL_MMU_ASID_BITS 8 /* number of bits in ASIDs */
+#define XCHAL_MMU_RINGS 4 /* number of rings (1..4) */
+#define XCHAL_MMU_RING_BITS 2 /* num of bits in RING field */
+
+#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
+
+
+#endif /* _XTENSA_CORE_CONFIGURATION_H */
diff --git a/target-xtensa/core-dc233c/gdb-config.c b/target-xtensa/core-dc233c/gdb-config.c
new file mode 100644
index 0000000..b632341
--- /dev/null
+++ b/target-xtensa/core-dc233c/gdb-config.c
@@ -0,0 +1,145 @@
+/* Configuration for the Xtensa architecture for GDB, the GNU debugger.
+
+ Copyright (c) 2003-2010 Tensilica Inc.
+
+ 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. */
+
+/* idx ofs bi sz al targno flags cp typ group name */
+XTREG(0, 0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc, 0, 0, 0, 0, 0, 0)
+XTREG(1, 4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0, 0, 0, 0, 0, 0, 0)
+XTREG(2, 8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1, 0, 0, 0, 0, 0, 0)
+XTREG(3, 12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2, 0, 0, 0, 0, 0, 0)
+XTREG(4, 16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3, 0, 0, 0, 0, 0, 0)
+XTREG(5, 20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4, 0, 0, 0, 0, 0, 0)
+XTREG(6, 24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5, 0, 0, 0, 0, 0, 0)
+XTREG(7, 28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6, 0, 0, 0, 0, 0, 0)
+XTREG(8, 32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7, 0, 0, 0, 0, 0, 0)
+XTREG(9, 36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8, 0, 0, 0, 0, 0, 0)
+XTREG(10, 40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9, 0, 0, 0, 0, 0, 0)
+XTREG(11, 44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10, 0, 0, 0, 0, 0, 0)
+XTREG(12, 48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11, 0, 0, 0, 0, 0, 0)
+XTREG(13, 52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12, 0, 0, 0, 0, 0, 0)
+XTREG(14, 56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13, 0, 0, 0, 0, 0, 0)
+XTREG(15, 60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14, 0, 0, 0, 0, 0, 0)
+XTREG(16, 64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15, 0, 0, 0, 0, 0, 0)
+XTREG(17, 68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16, 0, 0, 0, 0, 0, 0)
+XTREG(18, 72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17, 0, 0, 0, 0, 0, 0)
+XTREG(19, 76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18, 0, 0, 0, 0, 0, 0)
+XTREG(20, 80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19, 0, 0, 0, 0, 0, 0)
+XTREG(21, 84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20, 0, 0, 0, 0, 0, 0)
+XTREG(22, 88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21, 0, 0, 0, 0, 0, 0)
+XTREG(23, 92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22, 0, 0, 0, 0, 0, 0)
+XTREG(24, 96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23, 0, 0, 0, 0, 0, 0)
+XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24, 0, 0, 0, 0, 0, 0)
+XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25, 0, 0, 0, 0, 0, 0)
+XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26, 0, 0, 0, 0, 0, 0)
+XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27, 0, 0, 0, 0, 0, 0)
+XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28, 0, 0, 0, 0, 0, 0)
+XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29, 0, 0, 0, 0, 0, 0)
+XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30, 0, 0, 0, 0, 0, 0)
+XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31, 0, 0, 0, 0, 0, 0)
+XTREG(33, 132, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg, 0, 0, 0, 0, 0, 0)
+XTREG(34, 136, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend, 0, 0, 0, 0, 0, 0)
+XTREG(35, 140, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount, 0, 0, 0, 0, 0, 0)
+XTREG(36, 144, 6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar, 0, 0, 0, 0, 0, 0)
+XTREG(37, 148, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase, 0, 0, 0, 0, 0, 0)
+XTREG(38, 152, 3, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase, 0, 0, 0, 0, 0, 0)
+XTREG(39, 156, 8, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart, 0, 0, 0, 0, 0, 0)
+XTREG(40, 160, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176, 0, 0, 0, 0, 0, 0)
+XTREG(41, 164, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208, 0, 0, 0, 0, 0, 0)
+XTREG(42, 168, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps, 0, 0, 0, 0, 0, 0)
+XTREG(43, 172, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr, 0, 0, 0, 0, 0, 0)
+XTREG(44, 176, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1, 0, 0, 0, 0, 0, 0)
+XTREG(45, 180, 32, 4, 4, 0x0210, 0x0006, -1, 2, 0x1100, acclo, 0, 0, 0, 0, 0, 0)
+XTREG(46, 184, 8, 4, 4, 0x0211, 0x0006, -1, 2, 0x1100, acchi, 0, 0, 0, 0, 0, 0)
+XTREG(47, 188, 32, 4, 4, 0x0220, 0x0006, -1, 2, 0x1100, m0, 0, 0, 0, 0, 0, 0)
+XTREG(48, 192, 32, 4, 4, 0x0221, 0x0006, -1, 2, 0x1100, m1, 0, 0, 0, 0, 0, 0)
+XTREG(49, 196, 32, 4, 4, 0x0222, 0x0006, -1, 2, 0x1100, m2, 0, 0, 0, 0, 0, 0)
+XTREG(50, 200, 32, 4, 4, 0x0223, 0x0006, -1, 2, 0x1100, m3, 0, 0, 0, 0, 0, 0)
+XTREG(51, 204, 32, 4, 4, 0x03e6, 0x000e, -1, 3, 0x0110, expstate, 0, 0, 0, 0, 0, 0)
+XTREG(52, 208, 32, 4, 4, 0x0253, 0x0007, -2, 2, 0x1000, ptevaddr, 0, 0, 0, 0, 0, 0)
+XTREG(53, 212, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid, 0, 0, 0, 0, 0, 0)
+XTREG(54, 216, 32, 4, 4, 0x025a, 0x0007, -2, 2, 0x1000, rasid, 0, 0, 0, 0, 0, 0)
+XTREG(55, 220, 25, 4, 4, 0x025b, 0x0007, -2, 2, 0x1000, itlbcfg, 0, 0, 0, 0, 0, 0)
+XTREG(56, 224, 25, 4, 4, 0x025c, 0x0007, -2, 2, 0x1000, dtlbcfg, 0, 0, 0, 0, 0, 0)
+XTREG(57, 228, 2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable, 0, 0, 0, 0, 0, 0)
+XTREG(58, 232, 6, 4, 4, 0x0263, 0x0007, -2, 2, 0x1000, atomctl, 0, 0, 0, 0, 0, 0)
+XTREG(59, 236, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr, 0, 0, 0, 0, 0, 0)
+XTREG(60, 240, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0, 0, 0, 0, 0, 0, 0)
+XTREG(61, 244, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1, 0, 0, 0, 0, 0, 0)
+XTREG(62, 248, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0, 0, 0, 0, 0, 0, 0)
+XTREG(63, 252, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1, 0, 0, 0, 0, 0, 0)
+XTREG(64, 256, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0, 0, 0, 0, 0, 0, 0)
+XTREG(65, 260, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1, 0, 0, 0, 0, 0, 0)
+XTREG(66, 264, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1, 0, 0, 0, 0, 0, 0)
+XTREG(67, 268, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2, 0, 0, 0, 0, 0, 0)
+XTREG(68, 272, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3, 0, 0, 0, 0, 0, 0)
+XTREG(69, 276, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4, 0, 0, 0, 0, 0, 0)
+XTREG(70, 280, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5, 0, 0, 0, 0, 0, 0)
+XTREG(71, 284, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6, 0, 0, 0, 0, 0, 0)
+XTREG(72, 288, 32, 4, 4, 0x02b7, 0x0007, -2, 2, 0x1000, epc7, 0, 0, 0, 0, 0, 0)
+XTREG(73, 292, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc, 0, 0, 0, 0, 0, 0)
+XTREG(74, 296, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2, 0, 0, 0, 0, 0, 0)
+XTREG(75, 300, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3, 0, 0, 0, 0, 0, 0)
+XTREG(76, 304, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4, 0, 0, 0, 0, 0, 0)
+XTREG(77, 308, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5, 0, 0, 0, 0, 0, 0)
+XTREG(78, 312, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6, 0, 0, 0, 0, 0, 0)
+XTREG(79, 316, 19, 4, 4, 0x02c7, 0x0007, -2, 2, 0x1000, eps7, 0, 0, 0, 0, 0, 0)
+XTREG(80, 320, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1, 0, 0, 0, 0, 0, 0)
+XTREG(81, 324, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2, 0, 0, 0, 0, 0, 0)
+XTREG(82, 328, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3, 0, 0, 0, 0, 0, 0)
+XTREG(83, 332, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4, 0, 0, 0, 0, 0, 0)
+XTREG(84, 336, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5, 0, 0, 0, 0, 0, 0)
+XTREG(85, 340, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6, 0, 0, 0, 0, 0, 0)
+XTREG(86, 344, 32, 4, 4, 0x02d7, 0x0007, -2, 2, 0x1000, excsave7, 0, 0, 0, 0, 0, 0)
+XTREG(87, 348, 8, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable, 0, 0, 0, 0, 0, 0)
+XTREG(88, 352, 22, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt, 0, 0, 0, 0, 0, 0)
+XTREG(89, 356, 22, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset, 0, 0, 0, 0, 0, 0)
+XTREG(90, 360, 22, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear, 0, 0, 0, 0, 0, 0)
+XTREG(91, 364, 22, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable, 0, 0, 0, 0, 0, 0)
+XTREG(92, 368, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase, 0, 0, 0, 0, 0, 0)
+XTREG(93, 372, 6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause, 0, 0, 0, 0, 0, 0)
+XTREG(94, 376, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause, 0, 0, 0, 0, 0, 0)
+XTREG(95, 380, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount, 0, 0, 0, 0, 0, 0)
+XTREG(96, 384, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid, 0, 0, 0, 0, 0, 0)
+XTREG(97, 388, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount, 0, 0, 0, 0, 0, 0)
+XTREG(98, 392, 4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel, 0, 0, 0, 0, 0, 0)
+XTREG(99, 396, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr, 0, 0, 0, 0, 0, 0)
+XTREG(100, 400, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0, 0, 0, 0, 0, 0, 0)
+XTREG(101, 404, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1, 0, 0, 0, 0, 0, 0)
+XTREG(102, 408, 32, 4, 4, 0x02f2, 0x000f, -2, 2, 0x1000, ccompare2, 0, 0, 0, 0, 0, 0)
+XTREG(103, 412, 32, 4, 4, 0x02f4, 0x0007, -2, 2, 0x1000, misc0, 0, 0, 0, 0, 0, 0)
+XTREG(104, 416, 32, 4, 4, 0x02f5, 0x0007, -2, 2, 0x1000, misc1, 0, 0, 0, 0, 0, 0)
+XTREG(105, 420, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0, 0, 0, 0, 0, 0, 0)
+XTREG(106, 424, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1, 0, 0, 0, 0, 0, 0)
+XTREG(107, 428, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2, 0, 0, 0, 0, 0, 0)
+XTREG(108, 432, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3, 0, 0, 0, 0, 0, 0)
+XTREG(109, 436, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4, 0, 0, 0, 0, 0, 0)
+XTREG(110, 440, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5, 0, 0, 0, 0, 0, 0)
+XTREG(111, 444, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6, 0, 0, 0, 0, 0, 0)
+XTREG(112, 448, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7, 0, 0, 0, 0, 0, 0)
+XTREG(113, 452, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8, 0, 0, 0, 0, 0, 0)
+XTREG(114, 456, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9, 0, 0, 0, 0, 0, 0)
+XTREG(115, 460, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10, 0, 0, 0, 0, 0, 0)
+XTREG(116, 464, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11, 0, 0, 0, 0, 0, 0)
+XTREG(117, 468, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12, 0, 0, 0, 0, 0, 0)
+XTREG(118, 472, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13, 0, 0, 0, 0, 0, 0)
+XTREG(119, 476, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14, 0, 0, 0, 0, 0, 0)
+XTREG(120, 480, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15, 0, 0, 0, 0, 0, 0)
commit 11ea40905259f29e448af816ff00d9d9f0951818
Author: Andreas Färber <afaerber at suse.de>
Date: Sun Apr 15 18:51:01 2012 +0200
linux-user: Fix exit syscall with QOM CPU
For QOM'ified CPUs we cannot g_free() CPUArchState, we must
object_delete() the object it is embedded into.
Fixes LP#982321 (invalid free() while executing pacman with qemu-arm).
Reported-by: Serge Schneider <serge at xecdesign.com>
Reported-by: Russell Keith Davis <russell at russelldavis.org>
Signed-off-by: Andreas Färber <afaerber at suse.de>
Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
Tested-by: Serge Schneider <serge at xecdesign.com>
Tested-by: Russell Keith Davis <russell at russelldavis.org>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8a92162..7128618 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5045,7 +5045,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
NULL, NULL, 0);
}
thread_env = NULL;
+#ifdef ENV_GET_CPU
+ object_delete(OBJECT(ENV_GET_CPU(cpu_env)));
+#else
g_free(cpu_env);
+#endif
g_free(ts);
pthread_exit(NULL);
}
commit 45e45ed2d61fb287adf03e49c74c152bfd2c975a
Author: Juan Quintela <quintela at redhat.com>
Date: Mon Mar 19 23:57:36 2012 +0100
target-ppc/machine.c: Drop unnecessary ifdefs
machine.c is only compiled for softmmu targets, so checks for
!defined(CONFIG_USER_ONLY) are unnecessary and can be dropped.
Signed-off-by: Juan Quintela <quintela at redhat.com>
[AF: Use more verbose commit message suggested by PMM]
Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 70e2582..d6c2ee4 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -32,7 +32,6 @@ void cpu_save(QEMUFile *f, void *opaque)
}
qemu_put_be32s(f, &env->fpscr);
qemu_put_sbe32s(f, &env->access_type);
-#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
qemu_put_betls(f, &env->asr);
qemu_put_sbe32s(f, &env->slb_nr);
@@ -62,7 +61,6 @@ void cpu_save(QEMUFile *f, void *opaque)
}
for (i = 0; i < 4; i++)
qemu_put_betls(f, &env->pb[i]);
-#endif
for (i = 0; i < 1024; i++)
qemu_put_betls(f, &env->spr[i]);
qemu_put_be32s(f, &env->vscr);
@@ -72,7 +70,6 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32s(f, &env->flags);
qemu_put_sbe32s(f, &env->error_code);
qemu_put_be32s(f, &env->pending_interrupts);
-#if !defined(CONFIG_USER_ONLY)
qemu_put_be32s(f, &env->irq_input_state);
for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_put_betls(f, &env->excp_vectors[i]);
@@ -81,7 +78,6 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_betls(f, &env->ivor_mask);
qemu_put_betls(f, &env->ivpr_mask);
qemu_put_betls(f, &env->hreset_vector);
-#endif
qemu_put_betls(f, &env->nip);
qemu_put_betls(f, &env->hflags);
qemu_put_betls(f, &env->hflags_nmsr);
@@ -120,7 +116,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
}
qemu_get_be32s(f, &env->fpscr);
qemu_get_sbe32s(f, &env->access_type);
-#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
qemu_get_betls(f, &env->asr);
qemu_get_sbe32s(f, &env->slb_nr);
@@ -150,7 +145,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
}
for (i = 0; i < 4; i++)
qemu_get_betls(f, &env->pb[i]);
-#endif
for (i = 0; i < 1024; i++)
qemu_get_betls(f, &env->spr[i]);
ppc_store_sdr1(env, sdr1);
@@ -161,7 +155,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_be32s(f, &env->flags);
qemu_get_sbe32s(f, &env->error_code);
qemu_get_be32s(f, &env->pending_interrupts);
-#if !defined(CONFIG_USER_ONLY)
qemu_get_be32s(f, &env->irq_input_state);
for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_get_betls(f, &env->excp_vectors[i]);
@@ -170,7 +163,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_betls(f, &env->ivor_mask);
qemu_get_betls(f, &env->ivpr_mask);
qemu_get_betls(f, &env->hreset_vector);
-#endif
qemu_get_betls(f, &env->nip);
qemu_get_betls(f, &env->hflags);
qemu_get_betls(f, &env->hflags_nmsr);
commit a5cabbda760c798bb551d53a697058de28fce51c
Author: Meador Inge <meadori at codesourcery.com>
Date: Tue Apr 10 15:04:23 2012 -0500
target-ppc: Init dcache and icache size for e500 user mode
commit f7aa558396dd0f6b7a2b22c05cb503c655854102 pulled the dcache and icache
line size initialization inside of a '#if !defined(CONFIG_USER_ONLY)' block.
This is not correct because instructions like 'dcbz' need the dcache size
initialized even for user mode.
Signed-off-by: Meador Inge <meadori at codesourcery.com>
Cc: Varun Sethi <Varun.Sethi at freescale.com>
[AF: Simplify #ifdefs by using cache line size 32 for *-user as before]
Suggested-by: Scott Wood <scottwood at freescale.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index fdc0a5f..ba4b84d 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -4462,7 +4462,10 @@ static void init_proc_e500 (CPUPPCState *env, int version)
&spr_read_spefscr, &spr_write_spefscr,
0x00000000);
/* Memory management */
-#if !defined(CONFIG_USER_ONLY)
+#if defined(CONFIG_USER_ONLY)
+ env->dcache_line_size = 32;
+ env->icache_line_size = 32;
+#else /* !defined(CONFIG_USER_ONLY) */
env->nb_pids = 3;
env->nb_ways = 2;
env->id_tlbs = 0;
commit 5724753e6576fc26ff4a563a6c2ccb8ce3b02cb8
Author: Stefan Weil <sw at weilnetz.de>
Date: Sun Apr 15 16:13:48 2012 +0200
target-ppc: Fix type casts for w64 (uintptr_t)
This changes nothing for other hosts.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 025122d..fdc0a5f 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9504,12 +9504,12 @@ enum {
static inline int is_indirect_opcode (void *handler)
{
- return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
+ return ((uintptr_t)handler & 0x03) == PPC_INDIRECT;
}
static inline opc_handler_t **ind_table(void *handler)
{
- return (opc_handler_t **)((unsigned long)handler & ~3);
+ return (opc_handler_t **)((uintptr_t)handler & ~3);
}
/* Instruction table creation */
@@ -9528,7 +9528,7 @@ static int create_new_table (opc_handler_t **table, unsigned char idx)
tmp = malloc(0x20 * sizeof(opc_handler_t));
fill_new_table(tmp, 0x20);
- table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
+ table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
return 0;
}
commit a13895420561da4f8eae03f4d423a7c2fdb83f65
Author: Andreas Färber <afaerber at suse.de>
Date: Fri Apr 6 15:35:34 2012 +0200
target-ppc: QOM'ify CPU reset
Move code from cpu_state_reset() into ppc_cpu_reset().
Reorder #include of helper_regs.h to use it in translate_init.c.
Adjust whitespace and add braces.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: David Gibson <david at gibson.dropbear.id.au>
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index c5de0ea..c610ce3 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -3138,50 +3138,7 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr)
void cpu_state_reset(CPUPPCState *env)
{
- target_ulong msr;
-
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- msr = (target_ulong)0;
- if (0) {
- /* XXX: find a suitable condition to enable the hypervisor mode */
- msr |= (target_ulong)MSR_HVB;
- }
- msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
- msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
- msr |= (target_ulong)1 << MSR_EP;
-#if defined (DO_SINGLE_STEP) && 0
- /* Single step trace mode */
- msr |= (target_ulong)1 << MSR_SE;
- msr |= (target_ulong)1 << MSR_BE;
-#endif
-#if defined(CONFIG_USER_ONLY)
- msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
- msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
- msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
- msr |= (target_ulong)1 << MSR_PR;
-#else
- env->excp_prefix = env->hreset_excp_prefix;
- env->nip = env->hreset_vector | env->excp_prefix;
- if (env->mmu_model != POWERPC_MMU_REAL)
- ppc_tlb_invalidate_all(env);
-#endif
- env->msr = msr & env->msr_mask;
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64)
- env->msr |= (1ULL << MSR_SF);
-#endif
- hreg_compute_hflags(env);
- env->reserve_addr = (target_ulong)-1ULL;
- /* Be sure no exception or interrupt is pending */
- env->pending_interrupts = 0;
- env->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
- /* Flush all TLBs */
- tlb_flush(env, 1);
+ cpu_reset(ENV_GET_CPU(env));
}
CPUPPCState *cpu_ppc_init (const char *cpu_model)
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index c9a503a..cf59765 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -9306,8 +9306,8 @@ GEN_SPEOP_LDST(evstwwe, 0x1C, 2),
GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
};
-#include "translate_init.c"
#include "helper_regs.h"
+#include "translate_init.c"
/*****************************************************************************/
/* Misc PowerPC helpers */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 5a7ac77..025122d 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -10211,10 +10211,54 @@ static void ppc_cpu_reset(CPUState *s)
PowerPCCPU *cpu = POWERPC_CPU(s);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
+ target_ulong msr;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
pcc->parent_reset(s);
- cpu_state_reset(env);
+ msr = (target_ulong)0;
+ if (0) {
+ /* XXX: find a suitable condition to enable the hypervisor mode */
+ msr |= (target_ulong)MSR_HVB;
+ }
+ msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
+ msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
+ msr |= (target_ulong)1 << MSR_EP;
+#if defined(DO_SINGLE_STEP) && 0
+ /* Single step trace mode */
+ msr |= (target_ulong)1 << MSR_SE;
+ msr |= (target_ulong)1 << MSR_BE;
+#endif
+#if defined(CONFIG_USER_ONLY)
+ msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
+ msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
+ msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
+ msr |= (target_ulong)1 << MSR_PR;
+#else
+ env->excp_prefix = env->hreset_excp_prefix;
+ env->nip = env->hreset_vector | env->excp_prefix;
+ if (env->mmu_model != POWERPC_MMU_REAL) {
+ ppc_tlb_invalidate_all(env);
+ }
+#endif
+ env->msr = msr & env->msr_mask;
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ env->msr |= (1ULL << MSR_SF);
+ }
+#endif
+ hreg_compute_hflags(env);
+ env->reserve_addr = (target_ulong)-1ULL;
+ /* Be sure no exception or interrupt is pending */
+ env->pending_interrupts = 0;
+ env->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ /* Flush all TLBs */
+ tlb_flush(env, 1);
}
static void ppc_cpu_initfn(Object *obj)
commit 6cca7ad686de0270fe30ae303e31c6a27b53d7a9
Author: Andreas Färber <afaerber at suse.de>
Date: Fri Apr 6 15:09:01 2012 +0200
target-ppc: Start QOM'ifying CPU init
Move code not dependent on ppc_def_t from cpu_ppc_init() into an initfn.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: David Gibson <david at gibson.dropbear.id.au>
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 0d904dd..c5de0ea 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -3196,10 +3196,11 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU));
env = &cpu->env;
- cpu_exec_init(env);
+
if (tcg_enabled()) {
ppc_translate_init();
}
+
env->cpu_model_str = cpu_model;
cpu_ppc_register_internal(env, def);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index e4d15a5..5a7ac77 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -10217,6 +10217,14 @@ static void ppc_cpu_reset(CPUState *s)
cpu_state_reset(env);
}
+static void ppc_cpu_initfn(Object *obj)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(obj);
+ CPUPPCState *env = &cpu->env;
+
+ cpu_exec_init(env);
+}
+
static void ppc_cpu_class_init(ObjectClass *oc, void *data)
{
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -10230,6 +10238,7 @@ static const TypeInfo ppc_cpu_type_info = {
.name = TYPE_POWERPC_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(PowerPCCPU),
+ .instance_init = ppc_cpu_initfn,
.abstract = false,
.class_size = sizeof(PowerPCCPUClass),
.class_init = ppc_cpu_class_init,
commit 1d0cb67da9eff798420d0f6479fec6026c4dc41f
Author: Andreas Färber <afaerber at suse.de>
Date: Fri Apr 6 14:39:03 2012 +0200
target-ppc: QOM'ify CPU
Embed CPUPPCState as first member of PowerPCCPU.
Distinguish between "powerpc-cpu", "powerpc64-cpu" and
"embedded-powerpc-cpu".
Let CPUClass::reset() call cpu_state_reset() for now.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: David Gibson <david at gibson.dropbear.id.au>
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
new file mode 100644
index 0000000..fef6f95
--- /dev/null
+++ b/target-ppc/cpu-qom.h
@@ -0,0 +1,77 @@
+/*
+ * QEMU PowerPC CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_PPC_CPU_QOM_H
+#define QEMU_PPC_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#ifdef TARGET_PPC64
+#define TYPE_POWERPC_CPU "powerpc64-cpu"
+#elif defined(TARGET_PPCEMB)
+#define TYPE_POWERPC_CPU "embedded-powerpc-cpu"
+#else
+#define TYPE_POWERPC_CPU "powerpc-cpu"
+#endif
+
+#define POWERPC_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PowerPCCPUClass, (klass), TYPE_POWERPC_CPU)
+#define POWERPC_CPU(obj) \
+ OBJECT_CHECK(PowerPCCPU, (obj), TYPE_POWERPC_CPU)
+#define POWERPC_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PowerPCCPUClass, (obj), TYPE_POWERPC_CPU)
+
+/**
+ * PowerPCCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A PowerPC CPU model.
+ */
+typedef struct PowerPCCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} PowerPCCPUClass;
+
+/**
+ * PowerPCCPU:
+ * @env: #CPUPPCState
+ *
+ * A PowerPC CPU.
+ */
+typedef struct PowerPCCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUPPCState env;
+} PowerPCCPU;
+
+static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
+{
+ return POWERPC_CPU(container_of(env, PowerPCCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e))
+
+
+#endif
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 1d5c602..84c9674 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1096,6 +1096,8 @@ struct mmu_ctx_t {
};
#endif
+#include "cpu-qom.h"
+
/*****************************************************************************/
CPUPPCState *cpu_ppc_init (const char *cpu_model);
void ppc_translate_init(void);
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index b34dcbe..0d904dd 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -3186,6 +3186,7 @@ void cpu_state_reset(CPUPPCState *env)
CPUPPCState *cpu_ppc_init (const char *cpu_model)
{
+ PowerPCCPU *cpu;
CPUPPCState *env;
const ppc_def_t *def;
@@ -3193,7 +3194,8 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
if (!def)
return NULL;
- env = g_malloc0(sizeof(CPUPPCState));
+ cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU));
+ env = &cpu->env;
cpu_exec_init(env);
if (tcg_enabled()) {
ppc_translate_init();
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 067e07e..e4d15a5 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -10204,3 +10204,40 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
ppc_defs[i].name, ppc_defs[i].pvr);
}
}
+
+/* CPUClass::reset() */
+static void ppc_cpu_reset(CPUState *s)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(s);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ CPUPPCState *env = &cpu->env;
+
+ pcc->parent_reset(s);
+
+ cpu_state_reset(env);
+}
+
+static void ppc_cpu_class_init(ObjectClass *oc, void *data)
+{
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
+
+ pcc->parent_reset = cc->reset;
+ cc->reset = ppc_cpu_reset;
+}
+
+static const TypeInfo ppc_cpu_type_info = {
+ .name = TYPE_POWERPC_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(PowerPCCPU),
+ .abstract = false,
+ .class_size = sizeof(PowerPCCPUClass),
+ .class_init = ppc_cpu_class_init,
+};
+
+static void ppc_cpu_register_types(void)
+{
+ type_register_static(&ppc_cpu_type_info);
+}
+
+type_init(ppc_cpu_register_types)
commit 12b1143b2807a5b760e477fac0e1028a9760b6c6
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Wed Apr 4 15:02:05 2012 +1000
target-ppc: Add hooks for handling tcg and kvm limitations
On target-ppc, our table of CPU types and features encodes the features as
found on the hardware, regardless of whether these features are actually
usable under TCG or KVM. We already have cases where the information from
the cpu table must be fixed up to account for limitations in the emulation
method we're using. e.g. TCG does not support the DFP and VSX instructions
and KVM needs different numbering of the CPUs in order to tell it the
correct thread to core mappings.
This patch cleans up these hacks to handle emulation limitations by
consolidating them into a pair of functions specifically for the purpose.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
[AF: Style and typo fixes, rename new functions and drop ppc_def_t arg]
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index f61b8b2..b34dcbe 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -3198,15 +3198,6 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
if (tcg_enabled()) {
ppc_translate_init();
}
- /* Adjust cpu index for SMT */
-#if !defined(CONFIG_USER_ONLY)
- if (kvm_enabled()) {
- int smt = kvmppc_smt_threads();
-
- env->cpu_index = (env->cpu_index / smp_threads)*smt
- + (env->cpu_index % smp_threads);
- }
-#endif /* !CONFIG_USER_ONLY */
env->cpu_model_str = cpu_model;
cpu_ppc_register_internal(env, def);
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index d929213..c09cc39 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -27,6 +27,7 @@
#include "kvm.h"
#include "kvm_ppc.h"
#include "cpu.h"
+#include "cpus.h"
#include "device_tree.h"
#include "hw/sysbus.h"
#include "hw/spapr.h"
@@ -938,6 +939,19 @@ const ppc_def_t *kvmppc_host_cpu_def(void)
return spec;
}
+int kvmppc_fixup_cpu(CPUPPCState *env)
+{
+ int smt;
+
+ /* Adjust cpu index for SMT */
+ smt = kvmppc_smt_threads();
+ env->cpu_index = (env->cpu_index / smp_threads) * smt
+ + (env->cpu_index % smp_threads);
+
+ return 0;
+}
+
+
bool kvm_arch_stop_on_emulation_error(CPUPPCState *env)
{
return true;
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 8f1267c..34ecad3 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -29,6 +29,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
#endif /* !CONFIG_USER_ONLY */
const ppc_def_t *kvmppc_host_cpu_def(void);
+int kvmppc_fixup_cpu(CPUPPCState *env);
#else
@@ -95,6 +96,10 @@ static inline const ppc_def_t *kvmppc_host_cpu_def(void)
return NULL;
}
+static inline int kvmppc_fixup_cpu(CPUPPCState *env)
+{
+ return -1;
+}
#endif
#ifndef CONFIG_KVM
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index b1f8785..067e07e 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9889,6 +9889,28 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
+static int ppc_fixup_cpu(CPUPPCState *env)
+{
+ /* TCG doesn't (yet) emulate some groups of instructions that
+ * are implemented on some otherwise supported CPUs (e.g. VSX
+ * and decimal floating point instructions on POWER7). We
+ * remove unsupported instruction groups from the cpu state's
+ * instruction masks and hope the guest can cope. For at
+ * least the pseries machine, the unavailability of these
+ * instructions can be advertised to the guest via the device
+ * tree. */
+ if ((env->insns_flags & ~PPC_TCG_INSNS)
+ || (env->insns_flags2 & ~PPC_TCG_INSNS2)) {
+ fprintf(stderr, "Warning: Disabling some instructions which are not "
+ "emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")\n",
+ env->insns_flags & ~PPC_TCG_INSNS,
+ env->insns_flags2 & ~PPC_TCG_INSNS2);
+ }
+ env->insns_flags &= PPC_TCG_INSNS;
+ env->insns_flags2 &= PPC_TCG_INSNS2;
+ return 0;
+}
+
int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
{
env->msr_mask = def->msr_mask;
@@ -9897,25 +9919,22 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
env->bus_model = def->bus_model;
env->insns_flags = def->insns_flags;
env->insns_flags2 = def->insns_flags2;
- if (!kvm_enabled()) {
- /* TCG doesn't (yet) emulate some groups of instructions that
- * are implemented on some otherwise supported CPUs (e.g. VSX
- * and decimal floating point instructions on POWER7). We
- * remove unsupported instruction groups from the cpu state's
- * instruction masks and hope the guest can cope. For at
- * least the pseries machine, the unavailability of these
- * instructions can be advertise to the guest via the device
- * tree.
- *
- * FIXME: we should have a similar masking for CPU features
- * not accessible under KVM, but so far, there aren't any of
- * those. */
- env->insns_flags &= PPC_TCG_INSNS;
- env->insns_flags2 &= PPC_TCG_INSNS2;
- }
env->flags = def->flags;
env->bfd_mach = def->bfd_mach;
env->check_pow = def->check_pow;
+
+ if (kvm_enabled()) {
+ if (kvmppc_fixup_cpu(env) != 0) {
+ fprintf(stderr, "Unable to virtualize selected CPU with KVM\n");
+ exit(1);
+ }
+ } else {
+ if (ppc_fixup_cpu(env) != 0) {
+ fprintf(stderr, "Unable to emulate selected CPU with TCG\n");
+ exit(1);
+ }
+ }
+
if (create_ppc_opcodes(env, def) < 0)
return -1;
init_ppc_proc(env, def);
commit e2fbb432fc4ec64d0a53c41588ede31450b6c6a8
Author: Andreas Färber <afaerber at suse.de>
Date: Fri Apr 6 14:42:59 2012 +0200
target-ppc: Drop cpu_ppc_close()
It is unused, so avoid QOM'ifying it unneededly.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: David Gibson <david at gibson.dropbear.id.au>
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index e7fb364..1d5c602 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1100,7 +1100,6 @@ struct mmu_ctx_t {
CPUPPCState *cpu_ppc_init (const char *cpu_model);
void ppc_translate_init(void);
int cpu_ppc_exec (CPUPPCState *s);
-void cpu_ppc_close (CPUPPCState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index f0ea1c3..f61b8b2 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -3214,9 +3214,3 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
return env;
}
-
-void cpu_ppc_close (CPUPPCState *env)
-{
- /* Should also remove all opcode tables... */
- g_free(env);
-}
commit 5f2e2ba2625d6fa4ecbc2af86e076c20ab84c171
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Wed Apr 4 15:02:07 2012 +1000
pseries: Consolidate hack for RTAS display-character usage
Currently the pseries machine contains not one but two somewhat ugly hacks
to allow printing of early debug messages before the guest has properly
read the device tree.
First, we special case H_PUT_TERM_CHAR so that a vtermno of 0 (usually
invalid) will look for a suitable vty and use that. This supports Linux's
early debug code which will use H_PUT_TERM_CHAR with vtermno==0 before
reading the device tree. Second, we support the RTAS display-character call.
This takes no vtermno so we assume the address of the default first VTY.
This patch makes things more consistent by folding the second hack into the
first. Now, display-character uses the existing vty_lookup() function to
do the same search for a suitable VTY.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
index 480a4ae..ae18595 100644
--- a/hw/spapr_rtas.c
+++ b/hw/spapr_rtas.c
@@ -44,8 +44,7 @@ static void rtas_display_character(sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
uint8_t c = rtas_ld(args, 0);
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus,
- SPAPR_VTY_BASE_ADDRESS);
+ VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
if (!sdev) {
rtas_st(rets, 0, -1);
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index ae3283c..fd29c5e 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -117,6 +117,7 @@ uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr);
int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
+VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 60e22b1..a30c040 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -70,8 +70,6 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev)
}
/* Forward declaration */
-static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
-
static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -195,7 +193,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
return selected;
}
-static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
+VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
{
VIOsPAPRDevice *sdev;
commit 3b768df95a877577a9b8d7ea98166240b017ca84
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Wed Apr 4 15:02:06 2012 +1000
pseries: Remove unused fields from VIOsPAPRBus structure
The VIOsPAPRBus structure, used on the pseries machine contains some old
fields which are no longer used anywhere. This patch removes them.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index d8527be..ae3283c 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -89,8 +89,6 @@ struct VIOsPAPRDevice {
struct VIOsPAPRBus {
BusState bus;
- const char *dt_name, *dt_type, *dt_compatible;
- target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
};
commit c821a43c60e55fdfb8bc9c64696238e409d96192
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Thu Mar 29 08:39:47 2012 +1100
pseries: Implement RTAS system-reboot call
This patch adds the PAPR defined RTAS system-reboot call to the pseries
machine emulation, providing the guest with a way to trigger a reboot.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
index 0946585..480a4ae 100644
--- a/hw/spapr_rtas.c
+++ b/hw/spapr_rtas.c
@@ -112,6 +112,19 @@ static void rtas_power_off(sPAPREnvironment *spapr,
rtas_st(rets, 0, 0);
}
+static void rtas_system_reboot(sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ if (nargs != 0 || nret != 1) {
+ rtas_st(rets, 0, -3);
+ return;
+ }
+ qemu_system_reset_request();
+ rtas_st(rets, 0, 0);
+}
+
static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
@@ -294,6 +307,7 @@ static void core_rtas_register_types(void)
spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
spapr_rtas_register("set-time-of-day", rtas_set_time_of_day);
spapr_rtas_register("power-off", rtas_power_off);
+ spapr_rtas_register("system-reboot", rtas_system_reboot);
spapr_rtas_register("query-cpu-stopped-state",
rtas_query_cpu_stopped_state);
spapr_rtas_register("start-cpu", rtas_start_cpu);
commit 8e01f355db4c7e54b0877a6d9508e83d0afbc4b6
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Thu Mar 29 08:39:46 2012 +1100
pseries: Fix bug with reset of VIO CRQs
PAPR specifies a Command Response Queue (CRQ) mechanism used for virtual
IO, which we implement. However, we don't correctly clean up registered
CRQs when we reset the system.
This patch adds a reset handler to fix this bug. While we're at it, add
in some of the extra debug messages that were used to track the problem
down.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
[AF: Updated hcall_dprintf()s to not duplicate the function name]
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 1f67e64..0bf2c31 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -431,12 +431,13 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
/* Check if device supports CRQs */
if (!dev->crq.SendFunc) {
+ hcall_dprintf("Device does not support CRQ\n");
return H_NOT_FOUND;
}
-
/* Already a queue ? */
if (dev->crq.qsize) {
+ hcall_dprintf("CRQ already registered\n");
return H_RESOURCE;
}
dev->crq.qladdr = queue_addr;
@@ -449,6 +450,17 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
return H_SUCCESS;
}
+static target_ulong free_crq(VIOsPAPRDevice *dev)
+{
+ dev->crq.qladdr = 0;
+ dev->crq.qsize = 0;
+ dev->crq.qnext = 0;
+
+ dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg);
+
+ return H_SUCCESS;
+}
+
static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -460,13 +472,7 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
return H_PARAMETER;
}
- dev->crq.qladdr = 0;
- dev->crq.qsize = 0;
- dev->crq.qnext = 0;
-
- dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
-
- return H_SUCCESS;
+ return free_crq(dev);
}
static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
@@ -642,6 +648,15 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
return 0;
}
+static void spapr_vio_busdev_reset(void *opaque)
+{
+ VIOsPAPRDevice *dev = (VIOsPAPRDevice *)opaque;
+
+ if (dev->crq.qsize) {
+ free_crq(dev);
+ }
+}
+
static int spapr_vio_busdev_init(DeviceState *qdev)
{
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
@@ -670,6 +685,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
rtce_init(dev);
+ qemu_register_reset(spapr_vio_busdev_reset, dev);
+
return pc->init(dev);
}
commit d9599c9205089805cd6ef55985beeb06aef0c819
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Thu Mar 29 08:39:45 2012 +1100
pseries: Clean up hcall_dprintf() debugging messages
The pseries machine code has a number of debug messages for debugging PAPR
hypercalls, dependent on DEBUG_SPAPR_HCALLS. This patch cleans these
messages up a bit, by adding __func__ to the hcall_dprintf() macro and
simplifying up a number of the individual messages accordingly.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/spapr.h b/hw/spapr.h
index 11160b0..654a7a8 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -272,7 +272,7 @@ extern sPAPREnvironment *spapr;
#ifdef DEBUG_SPAPR_HCALLS
#define hcall_dprintf(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+ do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0)
#else
#define hcall_dprintf(fmt, ...) \
do { } while (0)
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index cfc7778..32dce17 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -279,21 +279,19 @@ static target_ulong h_register_logical_lan(CPUPPCState *env,
if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE),
SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
- hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for "
- "H_REGISTER_LOGICAL_LAN\n", buf_list);
+ hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
return H_PARAMETER;
}
filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE);
if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
- hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for "
- "H_REGISTER_LOGICAL_LAN\n", filter_list);
+ hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
return H_PARAMETER;
}
if (!(rec_queue & VLAN_BD_VALID)
|| (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
- hcall_dprintf("Bad receive queue for H_REGISTER_LOGICAL_LAN\n");
+ hcall_dprintf("Bad receive queue\n");
return H_PARAMETER;
}
@@ -358,13 +356,13 @@ static target_ulong h_add_logical_lan_buffer(CPUPPCState *env,
", 0x" TARGET_FMT_lx ")\n", reg, buf);
if (!sdev) {
- hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n");
+ hcall_dprintf("Bad device\n");
return H_PARAMETER;
}
if ((check_bd(dev, buf, 4) < 0)
|| (VLAN_BD_LEN(buf) < 16)) {
- hcall_dprintf("Bad buffer enqueued in h_add_logical_lan_buffer\n");
+ hcall_dprintf("Bad buffer enqueued\n");
return H_PARAMETER;
}
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index dbf5a90..1f67e64 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -204,8 +204,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr,
VIOsPAPR_RTCE *rtce;
if (!dev) {
- hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN "
- TARGET_FMT_lx "\n", liobn);
+ hcall_dprintf("LIOBN 0x" TARGET_FMT_lx " does not exist\n", liobn);
return H_PARAMETER;
}
@@ -217,8 +216,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr,
#endif
if (ioba >= dev->rtce_window_size) {
- hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
- TARGET_FMT_lx "\n", ioba);
+ hcall_dprintf("Out-of-bounds IOBA 0x" TARGET_FMT_lx "\n", ioba);
return H_PARAMETER;
}
@@ -414,22 +412,20 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
- hcall_dprintf("h_reg_crq on non-existent unit 0x"
- TARGET_FMT_lx "\n", reg);
+ hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
return H_PARAMETER;
}
/* We can't grok a queue size bigger than 256M for now */
if (queue_len < 0x1000 || queue_len > 0x10000000) {
- hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n",
- (unsigned long long)queue_len);
+ hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx
+ ")\n", queue_len);
return H_PARAMETER;
}
/* Check queue alignment */
if (queue_addr & 0xfff) {
- hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n",
- (unsigned long long)queue_addr);
+ hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr);
return H_PARAMETER;
}
@@ -460,8 +456,7 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
- hcall_dprintf("h_free_crq on non-existent unit 0x"
- TARGET_FMT_lx "\n", reg);
+ hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
return H_PARAMETER;
}
@@ -484,8 +479,7 @@ static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
uint64_t crq_mangle[2];
if (!dev) {
- hcall_dprintf("h_send_crq on non-existent unit 0x"
- TARGET_FMT_lx "\n", reg);
+ hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
return H_PARAMETER;
}
crq_mangle[0] = cpu_to_be64(msg_hi);
@@ -505,8 +499,7 @@ static target_ulong h_enable_crq(CPUPPCState *env, sPAPREnvironment *spapr,
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
- hcall_dprintf("h_enable_crq on non-existent unit 0x"
- TARGET_FMT_lx "\n", reg);
+ hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
return H_PARAMETER;
}
commit 52d631dcc70144b6ce8293db78cd6de635331c83
Author: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>
Date: Tue Mar 27 16:41:55 2012 +0100
PPC: Fix TLB invalidation bug within the PPC interrupt handler.
Commit 41557447d30eeb944e42069513df13585f5e6c7f also introduced a subtle TLB
flush bug. By applying a mask to the interrupt MSR which cleared the IR/DR
bits at the start of the interrupt handler, the logic towards the end of the
handler to force a TLB flush if either one of these bits were set would never
be triggered.
This patch simply changes the IR/DR bit check in the TLB flush logic to use
the original MSR value (albeit with some interrupt-specific bits cleared) so
that the IR/DR bits are preserved at the point where the check takes place.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>
Acked-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index e13b749..f0ea1c3 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -2960,7 +2960,7 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
if (asrr1 != -1)
env->spr[asrr1] = env->spr[srr1];
/* If we disactivated any translation, flush TLBs */
- if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
+ if (msr & ((1 << MSR_IR) | (1 << MSR_DR)))
tlb_flush(env, 1);
if (msr_ile) {
commit cdde6ffc27517bdf069734fbc5693ce2b14edc75
Author: Avi Kivity <avi at redhat.com>
Date: Wed Jan 4 16:28:42 2012 +0200
pci: fix corrupted pci conf index register by unaligned write
Commit d0ed8076cbdc261 converted the PCI config access to the memory
API, but also inadvertantly changed it to accept unaligned writes,
and corrupt the index register in the process. This causes a regression
booting NetBSD.
Fix by ignoring unaligned or non-dword writes.
https://bugs.launchpad.net/qemu/+bug/897771
Reported-by: Andreas Gustafsson <gson at gson.org>
Signed-off-by: Avi Kivity <avi at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_host.c b/hw/pci_host.c
index 44c6c20..8041778 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -101,6 +101,9 @@ static void pci_host_config_write(void *opaque, target_phys_addr_t addr,
PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
__func__, addr, len, val);
+ if (addr != 0 || len != 4) {
+ return;
+ }
s->config_reg = val;
}
commit 54bfa546a0b5af335128ef5c477f8af9834df498
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Apr 15 12:00:52 2012 +0300
acpi: explicitly account for >1 device per slot
Slot present bit is cleared apparently for each device. Hotplug and non
hotplug devices should not mix normally, and we only set the bit when we
add a device so it should all work out, but it's more robust to
explicitly account for more than one device per slot.
Acked-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 11c1f85..585da4e 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -287,6 +287,7 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
DeviceState *qdev, *next;
BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
int slot = ffs(slots) - 1;
+ bool slot_free = true;
/* Mark request as complete */
s->pci0_status.down &= ~(1U << slot);
@@ -294,11 +295,17 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
PCIDevice *dev = PCI_DEVICE(qdev);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) {
- s->pci0_slot_device_present &= ~(1U << slot);
- qdev_free(qdev);
+ if (PCI_SLOT(dev->devfn) == slot) {
+ if (pc->no_hotplug) {
+ slot_free = false;
+ } else {
+ qdev_free(qdev);
+ }
}
}
+ if (slot_free) {
+ s->pci0_slot_device_present &= ~(1U << slot);
+ }
}
static void piix4_update_hotplug(PIIX4PMState *s)
commit 9290f364c1f0c0a5a2ee8e03607f4804455c0d0e
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Thu Apr 5 11:07:28 2012 -0600
acpi_piix4: Re-define PCI hotplug eject register read
The PCI hotplug eject register has always returned 0, so let's redefine
it as a hotplug feature register. The existing model of using separate
up & down read-only registers and an eject via write to this register
becomes the base implementation. As we make use of new interfaces we'll
set bits here to allow the BIOS and AML implementation to optimize for
the platform implementation.
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/docs/specs/acpi_pci_hotplug.txt b/docs/specs/acpi_pci_hotplug.txt
index 1883d63..a839434 100644
--- a/docs/specs/acpi_pci_hotplug.txt
+++ b/docs/specs/acpi_pci_hotplug.txt
@@ -27,8 +27,16 @@ events. Read-only.
PCI device eject (IO port 0xae08-0xae0b, 4-byte access):
----------------------------------------
-Used by ACPI BIOS _EJ0 method to request device removal. One bit per slot.
-Reads return 0.
+Write: Used by ACPI BIOS _EJ0 method to request device removal.
+One bit per slot.
+
+Read: Hotplug features register. Used by platform to identify features
+available. Current base feature set (no bits set):
+ - Read-only "up" register @0xae00, 4-byte access, bit per slot
+ - Read-only "down" register @0xae04, 4-byte access, bit per slot
+ - Read/write "eject" register @0xae08, 4-byte access,
+ write: bit per slot eject, read: hotplug feature set
+ - Read-only hotplug capable register @0xae0c, 4-byte access, bit per slot
PCI removability status (IO port 0xae0c-0xae0f, 4-byte access):
-----------------------------------------------
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 5d3b0ba..11c1f85 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -511,9 +511,10 @@ static uint32_t pci_down_read(void *opaque, uint32_t addr)
return val;
}
-static uint32_t pciej_read(void *opaque, uint32_t addr)
+static uint32_t pci_features_read(void *opaque, uint32_t addr)
{
- PIIX4_DPRINTF("pciej read %x\n", addr);
+ /* No feature defined yet */
+ PIIX4_DPRINTF("pci_features_read %x\n", 0);
return 0;
}
@@ -545,7 +546,7 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
register_ioport_read(PCI_DOWN_BASE, 4, 4, pci_down_read, s);
register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, s);
- register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, s);
+ register_ioport_read(PCI_EJ_BASE, 4, 4, pci_features_read, s);
register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s);
commit 31745aabcd6dce5583dbd0e5ddee93ff9fdfe3e6
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Thu Apr 5 11:07:21 2012 -0600
acpi_piix4: Remove PCI_RMV_BASE write code
Clarify this register as read-only and remove write code. No
change in existing behavior.
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/docs/specs/acpi_pci_hotplug.txt b/docs/specs/acpi_pci_hotplug.txt
index 1e2c8a2..1883d63 100644
--- a/docs/specs/acpi_pci_hotplug.txt
+++ b/docs/specs/acpi_pci_hotplug.txt
@@ -34,4 +34,4 @@ PCI removability status (IO port 0xae0c-0xae0f, 4-byte access):
-----------------------------------------------
Used by ACPI BIOS _RMV method to indicate removability status to OS. One
-bit per slot.
+bit per slot. Read-only
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 0e7af51..5d3b0ba 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -531,11 +531,6 @@ static uint32_t pcirmv_read(void *opaque, uint32_t addr)
return s->pci0_hotplug_enable;
}
-static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
-{
- return;
-}
-
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
@@ -552,7 +547,6 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, s);
register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, s);
- register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s);
register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s);
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
commit 7faa8075d898ae56d2c533c530569bb25ab86eaf
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Thu Apr 5 11:07:15 2012 -0600
acpi_piix4: Fix PCI hotplug race
As Michael Tsirkin demonstrated, current PCI hotplug is vulnerable
to a few races. The first is a race with other hotplug operations
because we clear the up & down registers at each event. If a new
event comes before the last is processed, up/down is cleared and
the event is lost.
To fix this for the down register, we create a life cycle for
the event request that starts with the hot unplug request in
piix4_device_hotplug() and ends when the device is ejected.
This allows us to mask and clear individual bits, preserving them
against races. For the up register, we have no clear end point
for when the event is finished. We could modify the BIOS to
acknowledge the bit and clear it, but this creates BIOS compatibiliy
issues without offering a complete solution. Instead we note that
gratuitous ACPI device checks are not harmful, which allows us to
issue a device check for every slot. We know which slots are present
and we know which slots are hotpluggable, so we can easily reduce
this to a more manageable set for the guest.
The other race Michael noted was that an unplug request followed
by reset may also lose the eject notification, which may also
result in the eject request being lost which a subsequent add
or remove. Once we're in reset, the device is unused and we can
flush the queue of device removals ourselves. Previously if a
device_del was issued to a guest without ACPI PCI hotplug support,
it was necessary to shutdown the guest to recover the device.
With this, a guest reboot is sufficient.
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 5e8b261..0e7af51 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -48,7 +48,7 @@
#define PIIX4_PCI_HOTPLUG_STATUS 2
struct pci_status {
- uint32_t up;
+ uint32_t up; /* deprecated, maintained for migration compatibility */
uint32_t down;
};
@@ -70,6 +70,7 @@ typedef struct PIIX4PMState {
/* for pci hotplug */
struct pci_status pci0_status;
uint32_t pci0_hotplug_enable;
+ uint32_t pci0_slot_device_present;
} PIIX4PMState;
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
@@ -205,6 +206,17 @@ static void pm_write_config(PCIDevice *d,
pm_io_space_update((PIIX4PMState *)d);
}
+static void vmstate_pci_status_pre_save(void *opaque)
+{
+ struct pci_status *pci0_status = opaque;
+ PIIX4PMState *s = container_of(pci0_status, PIIX4PMState, pci0_status);
+
+ /* We no longer track up, so build a safe value for migrating
+ * to a version that still does... of course these might get lost
+ * by an old buggy implementation, but we try. */
+ pci0_status->up = s->pci0_slot_device_present & s->pci0_hotplug_enable;
+}
+
static int vmstate_acpi_post_load(void *opaque, int version_id)
{
PIIX4PMState *s = opaque;
@@ -241,6 +253,7 @@ static const VMStateDescription vmstate_pci_status = {
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
+ .pre_save = vmstate_pci_status_pre_save,
.fields = (VMStateField []) {
VMSTATE_UINT32(up, struct pci_status),
VMSTATE_UINT32(down, struct pci_status),
@@ -269,13 +282,38 @@ static const VMStateDescription vmstate_acpi = {
}
};
+static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
+{
+ DeviceState *qdev, *next;
+ BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
+ int slot = ffs(slots) - 1;
+
+ /* Mark request as complete */
+ s->pci0_status.down &= ~(1U << slot);
+
+ QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+ PCIDevice *dev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) {
+ s->pci0_slot_device_present &= ~(1U << slot);
+ qdev_free(qdev);
+ }
+ }
+}
+
static void piix4_update_hotplug(PIIX4PMState *s)
{
PCIDevice *dev = &s->dev;
BusState *bus = qdev_get_parent_bus(&dev->qdev);
DeviceState *qdev, *next;
+ /* Execute any pending removes during reset */
+ while (s->pci0_status.down) {
+ acpi_piix_eject_slot(s, s->pci0_status.down);
+ }
+
s->pci0_hotplug_enable = ~0;
+ s->pci0_slot_device_present = 0;
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
PCIDevice *pdev = PCI_DEVICE(qdev);
@@ -283,8 +321,10 @@ static void piix4_update_hotplug(PIIX4PMState *s)
int slot = PCI_SLOT(pdev->devfn);
if (pc->no_hotplug) {
- s->pci0_hotplug_enable &= ~(1 << slot);
+ s->pci0_hotplug_enable &= ~(1U << slot);
}
+
+ s->pci0_slot_device_present |= (1U << slot);
}
}
@@ -452,7 +492,11 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
static uint32_t pci_up_read(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
- uint32_t val = s->pci0_status.up;
+ uint32_t val;
+
+ /* Manufacture an "up" value to cause a device check on any hotplug
+ * slot with a device. Extra device checks are harmless. */
+ val = s->pci0_slot_device_present & s->pci0_hotplug_enable;
PIIX4_DPRINTF("pci_up_read %x\n", val);
return val;
@@ -475,18 +519,7 @@ static uint32_t pciej_read(void *opaque, uint32_t addr)
static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
{
- BusState *bus = opaque;
- DeviceState *qdev, *next;
- int slot = ffs(val) - 1;
-
- QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
- PCIDevice *dev = PCI_DEVICE(qdev);
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) {
- qdev_free(qdev);
- }
- }
-
+ acpi_piix_eject_slot(opaque, val);
PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val);
}
@@ -516,8 +549,8 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
register_ioport_read(PCI_UP_BASE, 4, 4, pci_up_read, s);
register_ioport_read(PCI_DOWN_BASE, 4, 4, pci_down_read, s);
- register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
- register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
+ register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, s);
+ register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, s);
register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s);
register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s);
@@ -528,13 +561,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
static void enable_device(PIIX4PMState *s, int slot)
{
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
- s->pci0_status.up |= (1 << slot);
+ s->pci0_slot_device_present |= (1U << slot);
}
static void disable_device(PIIX4PMState *s, int slot)
{
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
- s->pci0_status.down |= (1 << slot);
+ s->pci0_status.down |= (1U << slot);
}
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
@@ -548,11 +581,10 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
* it is present on boot, no hotplug event is necessary. We do send an
* event when the device is disabled later. */
if (state == PCI_COLDPLUG_ENABLED) {
+ s->pci0_slot_device_present |= (1U << slot);
return 0;
}
- s->pci0_status.up = 0;
- s->pci0_status.down = 0;
if (state == PCI_HOTPLUG_ENABLED) {
enable_device(s, slot);
} else {
commit ba737541edddf9d0026460eb7b1d1c599b4c8ae9
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Thu Apr 5 11:07:08 2012 -0600
acpi_piix4: Disallow write to up/down PCI hotplug registers
The write side of these registers is never used and actually can't be
used as defined because any read/modify/write sequence from the guest
potentially races with qemu. Drop the write support and define these
as read-only registers.
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/docs/specs/acpi_pci_hotplug.txt b/docs/specs/acpi_pci_hotplug.txt
index f0f74a7..1e2c8a2 100644
--- a/docs/specs/acpi_pci_hotplug.txt
+++ b/docs/specs/acpi_pci_hotplug.txt
@@ -15,14 +15,14 @@ PCI slot injection notification pending (IO port 0xae00-0xae03, 4-byte access):
Slot injection notification pending. One bit per slot.
Read by ACPI BIOS GPE.1 handler to notify OS of injection
-events.
+events. Read-only.
PCI slot removal notification (IO port 0xae04-0xae07, 4-byte access):
-----------------------------------------------------
Slot removal notification pending. One bit per slot.
Read by ACPI BIOS GPE.1 handler to notify OS of removal
-events.
+events. Read-only.
PCI device eject (IO port 0xae08-0xae0b, 4-byte access):
----------------------------------------
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 797ed24..5e8b261 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -40,7 +40,8 @@
#define GPE_BASE 0xafe0
#define GPE_LEN 4
-#define PCI_BASE 0xae00
+#define PCI_UP_BASE 0xae00
+#define PCI_DOWN_BASE 0xae04
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
@@ -448,38 +449,22 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
}
-static uint32_t pcihotplug_read(void *opaque, uint32_t addr)
+static uint32_t pci_up_read(void *opaque, uint32_t addr)
{
- uint32_t val = 0;
- struct pci_status *g = opaque;
- switch (addr) {
- case PCI_BASE:
- val = g->up;
- break;
- case PCI_BASE + 4:
- val = g->down;
- break;
- default:
- break;
- }
+ PIIX4PMState *s = opaque;
+ uint32_t val = s->pci0_status.up;
- PIIX4_DPRINTF("pcihotplug read %x == %x\n", addr, val);
+ PIIX4_DPRINTF("pci_up_read %x\n", val);
return val;
}
-static void pcihotplug_write(void *opaque, uint32_t addr, uint32_t val)
+static uint32_t pci_down_read(void *opaque, uint32_t addr)
{
- struct pci_status *g = opaque;
- switch (addr) {
- case PCI_BASE:
- g->up = val;
- break;
- case PCI_BASE + 4:
- g->down = val;
- break;
- }
-
- PIIX4_DPRINTF("pcihotplug write %x <== %d\n", addr, val);
+ PIIX4PMState *s = opaque;
+ uint32_t val = s->pci0_status.down;
+
+ PIIX4_DPRINTF("pci_down_read %x\n", val);
+ return val;
}
static uint32_t pciej_read(void *opaque, uint32_t addr)
@@ -523,14 +508,13 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{
- struct pci_status *pci0_status = &s->pci0_status;
register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s);
register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s);
acpi_gpe_blk(&s->ar, GPE_BASE);
- register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
- register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status);
+ register_ioport_read(PCI_UP_BASE, 4, 4, pci_up_read, s);
+ register_ioport_read(PCI_DOWN_BASE, 4, 4, pci_down_read, s);
register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
commit da12872a0973718997c00f1c1e8e5b91ee4c713a
Author: Hervé Poussineau <hpoussin at reactos.org>
Date: Sat Apr 14 22:51:33 2012 +0200
pcspk: initialize PC speaker if compiled in
PC speaker has been moved to target-independant code in 71093711589dafcb920dc3bc9bb811eaf8b14101,
so do not depend of target to include it or not.
Cc: malc <av1474 at comtv.ru>
Cc: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Herv? Poussineau <hpoussin at reactos.org>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/arch_init.c b/arch_init.c
index 595badf..9a35aee 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -475,7 +475,7 @@ struct soundhw {
static struct soundhw soundhw[] = {
#ifdef HAS_AUDIO_CHOICE
-#if defined(TARGET_I386) || defined(TARGET_MIPS)
+#ifdef CONFIG_PCSPK
{
"pcspk",
"PC speaker",
commit 2ad596079ecc9b379bcd253157bd0c911058e0e1
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Sat Mar 31 12:50:21 2012 +0200
tests: remove .SECONDARY special target
The special target should not be needed anymore, and caused (perhaps
due to a Make bug) a failure with "make -j2". In any case, the
main makefile is a better place for such special targets rather
than an included makefile.
Reported-by: Luiz Capitulino <lcapitulino at redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Tested-by: Luiz Capitulino <lcapitulino at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/Makefile b/tests/Makefile
index a98a848..baf1d70 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -92,8 +92,6 @@ check-help:
@echo "Default options are -k and (for make V=1) --verbose; they can be"
@echo "changed with variable GTESTER_OPTIONS."
-.SECONDARY:
-
SPEED = quick
GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
commit ad4ccc9370339e4f311a9e1d2c7cae77a9d45639
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Tue Apr 10 02:48:20 2012 +0400
target-xtensa: add test for IBREAK invalidation
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/tcg/xtensa/test_break.S b/tests/tcg/xtensa/test_break.S
index 8a8db80..7574cbe 100644
--- a/tests/tcg/xtensa/test_break.S
+++ b/tests/tcg/xtensa/test_break.S
@@ -91,6 +91,40 @@ test ibreak
assert eq, a2, a3
test_end
+test ibreak_remove
+ set_vector debug_vector, 3f
+ rsil a2, debug_level - 1
+ movi a2, 2f
+ wsr a2, ibreaka0
+ movi a3, 1
+1:
+ wsr a3, ibreakenable
+ isync
+2:
+ beqz a3, 4f
+ test_fail
+3:
+ assert eqi, a3, 1
+ rsr a2, ps
+ movi a3, 0x1f
+ and a2, a2, a3
+ movi a3, 0x10 | debug_level
+ assert eq, a2, a3
+ rsr a2, epc6
+ movi a3, 2b
+ assert eq, a2, a3
+ rsr a2, debugcause
+ movi a3, 0x2
+ assert eq, a2, a3
+
+ movi a2, 0x40000
+ wsr a2, ps
+ isync
+ movi a3, 0
+ j 1b
+4:
+test_end
+
test ibreak_priority
set_vector debug_vector, 2f
rsil a2, debug_level - 1
commit ec9fe93efe3a1211caa182771725833bbca733e0
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Tue Apr 10 02:48:19 2012 +0400
target-xtensa: add tests for LBEG/LEND invalidation
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/tcg/xtensa/test_loop.S b/tests/tcg/xtensa/test_loop.S
index a5ea933..5cead47 100644
--- a/tests/tcg/xtensa/test_loop.S
+++ b/tests/tcg/xtensa/test_loop.S
@@ -74,4 +74,54 @@ test loop_excm
assert eqi, a2, 1
test_end
+test lbeg_invalidation
+ movi a2, 0
+ movi a3, 1
+ movi a4, 1f
+ movi a5, 3f
+ wsr a3, lcount
+ wsr a4, lbeg
+ wsr a5, lend
+ isync
+ j 1f
+.align 4
+1:
+ addi a2, a2, 1
+ j 2f
+.align 4
+2:
+ addi a2, a2, 2
+ movi a3, 2b
+ wsr a3, lbeg
+ isync
+ nop
+3:
+ assert eqi, a2, 5
+test_end
+
+test lend_invalidation
+ movi a2, 0
+ movi a3, 5
+ movi a4, 1f
+ movi a5, 2f
+ wsr a3, lcount
+ wsr a4, lbeg
+ wsr a5, lend
+ isync
+ j 1f
+.align 4
+1:
+ addi a2, a2, 1
+2:
+ beqi a3, 3, 1f
+ assert eqi, a2, 6
+ movi a3, 3
+ wsr a3, lcount
+ wsr a4, lend
+ isync
+ j 1b
+1:
+ assert eqi, a2, 7
+test_end
+
test_suite_end
commit 3d0be8a5c135dadcfbd68ed354007a8cece98849
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Tue Apr 10 02:48:18 2012 +0400
target-xtensa: fix tb invalidation for IBREAK and LOOP
Instruction breakpoint/zero overhead loop handling code is built into
TBs pointed to by IBREAKA/LEND SRs. When these or related SRs get
changed TBs at virtual addresses corresponding to their old and their
new values must be invalidated.
Virtual address range is passed to the tb_invalidate_phys_page_range,
which is incorrect in system emulation mode.
To fix it use guest TLB/MMU to translate virtual address to physical
address.
However the guest may not have virtual-to-physical mapping at the moment
of IBREAKA/LEND change, thus this fix is not 100% accurate.
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index a6dd72d..364dc19 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -98,6 +98,18 @@ void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_id
env = saved_env;
}
+static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
+{
+ uint32_t paddr;
+ uint32_t page_size;
+ unsigned access;
+ int ret = xtensa_get_physical_addr(env, vaddr, 2, 0,
+ &paddr, &page_size, &access);
+ if (ret == 0) {
+ tb_invalidate_phys_addr(paddr);
+ }
+}
+
void HELPER(exception)(uint32_t excp)
{
env->exception_index = excp;
@@ -357,8 +369,7 @@ void HELPER(movsp)(uint32_t pc)
void HELPER(wsr_lbeg)(uint32_t v)
{
if (env->sregs[LBEG] != v) {
- tb_invalidate_phys_page_range(
- env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
env->sregs[LBEG] = v;
}
}
@@ -366,11 +377,9 @@ void HELPER(wsr_lbeg)(uint32_t v)
void HELPER(wsr_lend)(uint32_t v)
{
if (env->sregs[LEND] != v) {
- tb_invalidate_phys_page_range(
- env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
env->sregs[LEND] = v;
- tb_invalidate_phys_page_range(
- env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
}
}
@@ -691,8 +700,7 @@ void HELPER(wsr_ibreakenable)(uint32_t v)
for (i = 0; i < env->config->nibreak; ++i) {
if (change & (1 << i)) {
- tb_invalidate_phys_page_range(
- env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
+ tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]);
}
}
env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1);
@@ -701,9 +709,8 @@ void HELPER(wsr_ibreakenable)(uint32_t v)
void HELPER(wsr_ibreaka)(uint32_t i, uint32_t v)
{
if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) {
- tb_invalidate_phys_page_range(
- env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
- tb_invalidate_phys_page_range(v, v + 1, 0);
+ tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]);
+ tb_invalidate_virtual_addr(env, v);
}
env->sregs[IBREAKA + i] = v;
}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 492dbcc..6900123 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -459,11 +459,13 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
gen_helper_wsr_lbeg(s);
+ gen_jumpi_check_loop_end(dc, 0);
}
static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
gen_helper_wsr_lend(s);
+ gen_jumpi_check_loop_end(dc, 0);
}
static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
commit 1e7855a558085d6acd0aba4e3278b594d05df1ec
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Tue Apr 10 02:48:17 2012 +0400
exec: provide tb_invalidate_phys_addr function
Allow TB invalidation by its physical address, extract implementation
from the breakpoint_invalidate function.
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/exec-all.h b/exec-all.h
index fccce88..6bcc075 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -102,6 +102,7 @@ void tlb_flush(CPUArchState *env, int flush_global);
void tlb_set_page(CPUArchState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int mmu_idx, target_ulong size);
+void tb_invalidate_phys_addr(target_phys_addr_t addr);
#endif
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
diff --git a/exec.c b/exec.c
index 63a0d2f..68b8a6a 100644
--- a/exec.c
+++ b/exec.c
@@ -1463,13 +1463,11 @@ static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
tb_invalidate_phys_page_range(pc, pc + 1, 0);
}
#else
-static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+void tb_invalidate_phys_addr(target_phys_addr_t addr)
{
- target_phys_addr_t addr;
ram_addr_t ram_addr;
MemoryRegionSection *section;
- addr = cpu_get_phys_page_debug(env, pc);
section = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!(memory_region_is_ram(section->mr)
|| (section->mr->rom_device && section->mr->readable))) {
@@ -1479,6 +1477,11 @@ static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+ section_addr(section, addr);
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
}
+
+static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+{
+ tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc));
+}
#endif
#endif /* TARGET_HAS_ICE */
commit 2050396801ca0c8359364d61eaadece951006057
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Mon Apr 9 14:20:20 2012 +0000
Use uintptr_t for various op related functions
Use uintptr_t instead of void * or unsigned long in
several op related functions, env->mem_io_pc and
GETPC() macro.
Reviewed-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/cpu-defs.h b/cpu-defs.h
index 3268968..88d8093 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -166,8 +166,8 @@ typedef struct CPUWatchpoint {
/* in order to avoid passing too many arguments to the MMIO \
helpers, we store some rarely used information in the CPU \
context) */ \
- unsigned long mem_io_pc; /* host pc at which the memory was \
- accessed */ \
+ uintptr_t mem_io_pc; /* host pc at which the memory was \
+ accessed */ \
target_ulong mem_io_vaddr; /* target virtual addr at which the \
memory was accessed */ \
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
diff --git a/exec-all.h b/exec-all.h
index fa7bdfe..fccce88 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -87,7 +87,7 @@ int cpu_gen_code(CPUArchState *env, struct TranslationBlock *tb,
int cpu_restore_state(struct TranslationBlock *tb,
CPUArchState *env, uintptr_t searched_pc);
void QEMU_NORETURN cpu_resume_from_signal(CPUArchState *env1, void *puc);
-void QEMU_NORETURN cpu_io_recompile(CPUArchState *env, void *retaddr);
+void QEMU_NORETURN cpu_io_recompile(CPUArchState *env, uintptr_t retaddr);
TranslationBlock *tb_gen_code(CPUArchState *env,
target_ulong pc, target_ulong cs_base, int flags,
int cflags);
@@ -287,13 +287,13 @@ extern void *tci_tb_ptr;
# endif
#elif defined(__s390__) && !defined(__s390x__)
# define GETPC() \
- ((void *)(((uintptr_t)__builtin_return_address(0) & 0x7fffffffUL) - 1))
+ (((uintptr_t)__builtin_return_address(0) & 0x7fffffffUL) - 1)
#elif defined(__arm__)
/* Thumb return addresses have the low bit set, so we need to subtract two.
This is still safe in ARM mode because instructions are 4 bytes. */
-# define GETPC() ((void *)((uintptr_t)__builtin_return_address(0) - 2))
+# define GETPC() ((uintptr_t)__builtin_return_address(0) - 2)
#else
-# define GETPC() ((void *)((uintptr_t)__builtin_return_address(0) - 1))
+# define GETPC() ((uintptr_t)__builtin_return_address(0) - 1)
#endif
#if !defined(CONFIG_USER_ONLY)
@@ -305,7 +305,7 @@ void io_mem_write(struct MemoryRegion *mr, target_phys_addr_t addr,
uint64_t value, unsigned size);
void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr);
+ uintptr_t retaddr);
#include "softmmu_defs.h"
diff --git a/exec.c b/exec.c
index 03d3a6b..63a0d2f 100644
--- a/exec.c
+++ b/exec.c
@@ -1221,7 +1221,7 @@ static inline void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
#if !defined(CONFIG_SOFTMMU)
static void tb_invalidate_phys_page(tb_page_addr_t addr,
- unsigned long pc, void *puc)
+ uintptr_t pc, void *puc)
{
TranslationBlock *tb;
PageDesc *p;
@@ -4477,20 +4477,20 @@ int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr,
/* in deterministic execution mode, instructions doing device I/Os
must be at the end of the TB */
-void cpu_io_recompile(CPUArchState *env, void *retaddr)
+void cpu_io_recompile(CPUArchState *env, uintptr_t retaddr)
{
TranslationBlock *tb;
uint32_t n, cflags;
target_ulong pc, cs_base;
uint64_t flags;
- tb = tb_find_pc((uintptr_t)retaddr);
+ tb = tb_find_pc(retaddr);
if (!tb) {
cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
- retaddr);
+ (void *)retaddr);
}
n = env->icount_decr.u16.low + tb->icount;
- cpu_restore_state(tb, env, (unsigned long)retaddr);
+ cpu_restore_state(tb, env, retaddr);
/* Calculate how many instructions had been executed before the fault
occurred. */
n = n - env->icount_decr.u16.low;
@@ -4638,7 +4638,7 @@ bool virtio_is_big_endian(void)
#define MMUSUFFIX _cmmu
#undef GETPC
-#define GETPC() NULL
+#define GETPC() ((uintptr_t)0)
#define env cpu_single_env
#define SOFTMMU_CODE_ACCESS
diff --git a/softmmu_template.h b/softmmu_template.h
index afcab1e..b285d78 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -69,17 +69,17 @@
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM
target_ulong addr,
int mmu_idx,
- void *retaddr);
+ uintptr_t retaddr);
static inline DATA_TYPE glue(io_read, SUFFIX)(ENV_PARAM
target_phys_addr_t physaddr,
target_ulong addr,
- void *retaddr)
+ uintptr_t retaddr)
{
DATA_TYPE res;
MemoryRegion *mr = iotlb_to_region(physaddr);
physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
- env->mem_io_pc = (unsigned long)retaddr;
+ env->mem_io_pc = retaddr;
if (mr != &io_mem_ram && mr != &io_mem_rom
&& mr != &io_mem_unassigned
&& mr != &io_mem_notdirty
@@ -113,7 +113,7 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM
target_ulong tlb_addr;
target_phys_addr_t ioaddr;
unsigned long addend;
- void *retaddr;
+ uintptr_t retaddr;
/* test if there is match for unaligned or IO access */
/* XXX: could done more in memory macro in a non portable way */
@@ -166,7 +166,7 @@ static DATA_TYPE
glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM
target_ulong addr,
int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
DATA_TYPE res, res1, res2;
int index, shift;
@@ -219,13 +219,13 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM
target_ulong addr,
DATA_TYPE val,
int mmu_idx,
- void *retaddr);
+ uintptr_t retaddr);
static inline void glue(io_write, SUFFIX)(ENV_PARAM
target_phys_addr_t physaddr,
DATA_TYPE val,
target_ulong addr,
- void *retaddr)
+ uintptr_t retaddr)
{
MemoryRegion *mr = iotlb_to_region(physaddr);
@@ -238,7 +238,7 @@ static inline void glue(io_write, SUFFIX)(ENV_PARAM
}
env->mem_io_vaddr = addr;
- env->mem_io_pc = (unsigned long)retaddr;
+ env->mem_io_pc = retaddr;
#if SHIFT <= 2
io_mem_write(mr, physaddr, val, 1 << SHIFT);
#else
@@ -260,7 +260,7 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM
target_phys_addr_t ioaddr;
unsigned long addend;
target_ulong tlb_addr;
- void *retaddr;
+ uintptr_t retaddr;
int index;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@@ -310,7 +310,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM
target_ulong addr,
DATA_TYPE val,
int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
target_phys_addr_t ioaddr;
unsigned long addend;
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 74bf7f7..fd578ce 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -433,9 +433,9 @@ int cpu_alpha_handle_mmu_fault (CPUAlphaState *env, uint64_t address, int rw,
int mmu_idx);
#define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
void do_interrupt (CPUAlphaState *env);
-void do_restore_state(CPUAlphaState *, void *retaddr);
-void QEMU_NORETURN dynamic_excp(CPUAlphaState *, void *, int, int);
-void QEMU_NORETURN arith_excp(CPUAlphaState *, void *, int, uint64_t);
+void do_restore_state(CPUAlphaState *, uintptr_t retaddr);
+void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int);
+void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t);
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env);
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val);
diff --git a/target-alpha/fpu_helper.c b/target-alpha/fpu_helper.c
index dda1103..fe988ec 100644
--- a/target-alpha/fpu_helper.c
+++ b/target-alpha/fpu_helper.c
@@ -44,7 +44,7 @@ uint32_t helper_fp_exc_get(CPUAlphaState *env)
return get_float_exception_flags(&FP_STATUS);
}
-static inline void inline_fp_exc_raise(CPUAlphaState *env, void *retaddr,
+static inline void inline_fp_exc_raise(CPUAlphaState *env, uintptr_t retaddr,
uint32_t exc, uint32_t regno)
{
if (exc) {
@@ -160,7 +160,7 @@ static uint64_t float32_to_f(float32 fa)
return r;
}
-static float32 f_to_float32(CPUAlphaState *env, void *retaddr, uint64_t a)
+static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
{
uint32_t exp, mant_sig;
CPU_FloatU r;
@@ -291,7 +291,7 @@ static uint64_t float64_to_g(float64 fa)
return r;
}
-static float64 g_to_float64(CPUAlphaState *env, void *retaddr, uint64_t a)
+static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
{
uint64_t exp, mant_sig;
CPU_DoubleU r;
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 765e650..81d4763 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -494,13 +494,12 @@ void cpu_dump_state (CPUAlphaState *env, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, "\n");
}
-void do_restore_state(CPUAlphaState *env, void *retaddr)
+void do_restore_state(CPUAlphaState *env, uintptr_t retaddr)
{
- uintptr_t pc = (uintptr_t)retaddr;
- if (pc) {
- TranslationBlock *tb = tb_find_pc(pc);
+ if (retaddr) {
+ TranslationBlock *tb = tb_find_pc(retaddr);
if (tb) {
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
}
@@ -515,7 +514,7 @@ void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
}
/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
-void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, void *retaddr,
+void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
int excp, int error)
{
env->exception_index = excp;
@@ -524,7 +523,7 @@ void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, void *retaddr,
cpu_loop_exit(env);
}
-void QEMU_NORETURN arith_excp(CPUAlphaState *env, void *retaddr,
+void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
int exc, uint64_t mask)
{
env->trap_arg0 = exc;
diff --git a/target-alpha/mem_helper.c b/target-alpha/mem_helper.c
index dd5ca49..87cada4 100644
--- a/target-alpha/mem_helper.c
+++ b/target-alpha/mem_helper.c
@@ -89,7 +89,7 @@ uint64_t helper_stq_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
}
static void do_unaligned_access(CPUAlphaState *env, target_ulong addr,
- int is_write, int is_user, void *retaddr)
+ int is_write, int is_user, uintptr_t retaddr)
{
uint64_t pc;
uint32_t insn;
@@ -112,7 +112,7 @@ void cpu_unassigned_access(CPUAlphaState *env, target_phys_addr_t addr,
{
env->trap_arg0 = addr;
env->trap_arg1 = is_write;
- dynamic_excp(env, NULL, EXCP_MCHK, 0);
+ dynamic_excp(env, 0, EXCP_MCHK, 0);
}
#include "softmmu_exec.h"
@@ -137,7 +137,7 @@ void cpu_unassigned_access(CPUAlphaState *env, target_phys_addr_t addr,
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUAlphaState *env, target_ulong addr, int is_write,
- int mmu_idx, void *retaddr)
+ int mmu_idx, uintptr_t retaddr)
{
int ret;
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index c728432..b53369d 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -76,11 +76,10 @@ uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUARMState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
@@ -89,12 +88,11 @@ void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx,
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
raise_exception(env->exception_index);
diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c
index c568e2b..b92c106 100644
--- a/target-cris/op_helper.c
+++ b/target-cris/op_helper.c
@@ -57,28 +57,26 @@
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUCRISState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUCRISState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
env = env1;
- D_LOG("%s pc=%x tpc=%x ra=%x\n", __func__,
- env->pc, env->debug1, retaddr);
+ D_LOG("%s pc=%x tpc=%x ra=%p\n", __func__,
+ env->pc, env->debug1, (void *)retaddr);
ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
/* Evaluate flags after retranslation. */
helper_top_evaluate_flags();
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index c04ae44..bc3b94e 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -5003,11 +5003,10 @@ void helper_boundl(target_ulong a0, int v)
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUX86State *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
int ret;
- unsigned long pc;
CPUX86State *saved_env;
saved_env = env;
@@ -5017,12 +5016,11 @@ void tlb_fill(CPUX86State *env1, target_ulong addr, int is_write, int mmu_idx,
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
raise_exception_err(env->exception_index, env->error_code);
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
index e9c9638..51edc1a 100644
--- a/target-lm32/op_helper.c
+++ b/target-lm32/op_helper.c
@@ -76,11 +76,10 @@ uint32_t helper_rcsr_jrx(void)
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPULM32State *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPULM32State *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
@@ -90,12 +89,11 @@ void tlb_fill(CPULM32State *env1, target_ulong addr, int is_write, int mmu_idx,
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
cpu_loop_exit(env);
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index bc8c1f0..1971a57 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -56,11 +56,10 @@ extern int semihosting_enabled;
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUM68KState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
@@ -69,12 +68,11 @@ void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int mmu_idx,
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
cpu_loop_exit(env);
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index a83da8d..3b1f072 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -44,11 +44,10 @@
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUMBState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUMBState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
@@ -58,12 +57,11 @@ void tlb_fill(CPUMBState *env1, target_ulong addr, int is_write, int mmu_idx,
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
cpu_loop_exit(env);
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index ce01225..bca1d70 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -101,11 +101,10 @@ void helper_raise_exception (uint32_t exception)
}
#if !defined(CONFIG_USER_ONLY)
-static void do_restore_state (void *pc_ptr)
+static void do_restore_state(uintptr_t pc)
{
TranslationBlock *tb;
- unsigned long pc = (unsigned long) pc_ptr;
-
+
tb = tb_find_pc (pc);
if (tb) {
cpu_restore_state(tb, env, pc);
@@ -2293,7 +2292,7 @@ void helper_wait (void)
#if !defined(CONFIG_USER_ONLY)
static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
- int is_user, void *retaddr);
+ int is_user, uintptr_t retaddr);
#define MMUSUFFIX _mmu
#define ALIGNED_ONLY
@@ -2310,7 +2309,8 @@ static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
#define SHIFT 3
#include "softmmu_template.h"
-static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
+static void do_unaligned_access(target_ulong addr, int is_write,
+ int is_user, uintptr_t retaddr)
{
env->CP0_BadVAddr = addr;
do_restore_state (retaddr);
@@ -2318,11 +2318,10 @@ static void do_unaligned_access (target_ulong addr, int is_write, int is_user, v
}
void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUMIPSState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
@@ -2331,12 +2330,11 @@ void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx,
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
helper_raise_exception_err(env->exception_index, env->error_code);
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 40927b6..4ef2332 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -3715,11 +3715,10 @@ uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUPPCState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
@@ -3728,12 +3727,11 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (likely(tb)) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
helper_raise_exception_err(env->exception_index, env->error_code);
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 18fdbb2..7b72473 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -57,11 +57,10 @@
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUS390XState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
@@ -70,12 +69,11 @@ void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (likely(tb)) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
cpu_loop_exit(env);
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index 30f762f..4054791 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -22,18 +22,16 @@
#include "dyngen-exec.h"
#include "helper.h"
-static void cpu_restore_state_from_retaddr(void *retaddr)
+static void cpu_restore_state_from_retaddr(uintptr_t retaddr)
{
TranslationBlock *tb;
- unsigned long pc;
if (retaddr) {
- pc = (unsigned long) retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
}
@@ -56,7 +54,7 @@ static void cpu_restore_state_from_retaddr(void *retaddr)
#include "softmmu_template.h"
void tlb_fill(CPUSH4State *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
CPUSH4State *saved_env;
int ret;
@@ -84,7 +82,7 @@ void helper_ldtlb(void)
#endif
}
-static inline void raise_exception(int index, void *retaddr)
+static inline void raise_exception(int index, uintptr_t retaddr)
{
env->exception_index = index;
cpu_restore_state_from_retaddr(retaddr);
@@ -447,7 +445,7 @@ void helper_ld_fpscr(uint32_t val)
set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
}
-static void update_fpscr(void *retaddr)
+static void update_fpscr(uintptr_t retaddr)
{
int xcpt, cause, enable;
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 865288c..29c63c7 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -702,7 +702,7 @@ trap_state* cpu_tsptr(CPUSPARCState* env);
#endif
void QEMU_NORETURN do_unaligned_access(CPUSPARCState *env, target_ulong addr,
int is_write, int is_user,
- void *retaddr);
+ uintptr_t retaddr);
#define TB_FLAG_FPU_ENABLED (1 << 4)
#define TB_FLAG_AM_ENABLED (1 << 5)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 1418205..04ffddf 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -2376,25 +2376,23 @@ void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr,
#if !defined(CONFIG_USER_ONLY)
/* XXX: make it generic ? */
-static void cpu_restore_state2(CPUSPARCState *env, void *retaddr)
+static void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr)
{
TranslationBlock *tb;
- unsigned long pc;
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
}
void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write,
- int is_user, void *retaddr)
+ int is_user, uintptr_t retaddr)
{
#ifdef DEBUG_UNALIGNED
printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
@@ -2409,7 +2407,7 @@ void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write,
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUSPARCState *env, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
int ret;
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 806384f..a6dd72d 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -31,7 +31,7 @@
#include "host-utils.h"
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
- void *retaddr);
+ uintptr_t retaddr);
#define ALIGNED_ONLY
#define MMUSUFFIX _mmu
@@ -48,10 +48,9 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
#define SHIFT 3
#include "softmmu_template.h"
-static void do_restore_state(void *pc_ptr)
+static void do_restore_state(uintptr_t pc)
{
TranslationBlock *tb;
- uint32_t pc = (uint32_t)(intptr_t)pc_ptr;
tb = tb_find_pc(pc);
if (tb) {
@@ -60,7 +59,7 @@ static void do_restore_state(void *pc_ptr)
}
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
- void *retaddr)
+ uintptr_t retaddr)
{
if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
!xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
@@ -71,7 +70,7 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
}
void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
CPUXtensaState *saved_env = env;
diff --git a/user-exec.c b/user-exec.c
index cd905ff..be6bc4f 100644
--- a/user-exec.c
+++ b/user-exec.c
@@ -82,7 +82,7 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc)
the effective address of the memory exception. 'is_write' is 1 if a
write caused the exception and otherwise 0'. 'old_set' is the
signal set which should be restored */
-static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
commit d1b719e98ce8b506d122a845d405f941a7a497c1
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Sat Mar 3 04:52:56 2012 +0000
coroutine-gthread.c: Avoid threading APIs deprecated in GLib 2.31
The GLib threading APIs were revamped in GLib 2.31 and a number
of the old interfaces were deprecated, which means they provoke
compilation warnings (errors if -Werror) now. Add support for the
new interfaces while retaining the old ones so we can still compile
on older versions of GLib too.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/coroutine-gthread.c b/coroutine-gthread.c
index 662801b..30c24c9 100644
--- a/coroutine-gthread.c
+++ b/coroutine-gthread.c
@@ -26,13 +26,93 @@ typedef struct {
Coroutine base;
GThread *thread;
bool runnable;
+ bool free_on_thread_exit;
CoroutineAction action;
} CoroutineGThread;
-static GCond *coroutine_cond;
static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
+
+/* GLib 2.31 and beyond deprecated various parts of the thread API,
+ * but the new interfaces are not available in older GLib versions
+ * so we have to cope with both.
+ */
+#if GLIB_CHECK_VERSION(2, 31, 0)
+/* Default zero-initialisation is sufficient for 2.31+ GCond */
+static GCond the_coroutine_cond;
+static GCond *coroutine_cond = &the_coroutine_cond;
+static inline void init_coroutine_cond(void)
+{
+}
+
+/* Awkwardly, the GPrivate API doesn't provide a way to update the
+ * GDestroyNotify handler for the coroutine key dynamically. So instead
+ * we track whether or not the CoroutineGThread should be freed on
+ * thread exit / coroutine key update using the free_on_thread_exit
+ * field.
+ */
+static void coroutine_destroy_notify(gpointer data)
+{
+ CoroutineGThread *co = data;
+ if (co && co->free_on_thread_exit) {
+ g_free(co);
+ }
+}
+
+static GPrivate coroutine_key = G_PRIVATE_INIT(coroutine_destroy_notify);
+
+static inline CoroutineGThread *get_coroutine_key(void)
+{
+ return g_private_get(&coroutine_key);
+}
+
+static inline void set_coroutine_key(CoroutineGThread *co,
+ bool free_on_thread_exit)
+{
+ /* Unlike g_static_private_set() this does not call the GDestroyNotify
+ * if the previous value of the key was NULL. Fortunately we only need
+ * the GDestroyNotify in the non-NULL key case.
+ */
+ co->free_on_thread_exit = free_on_thread_exit;
+ g_private_replace(&coroutine_key, co);
+}
+
+static inline GThread *create_thread(GThreadFunc func, gpointer data)
+{
+ return g_thread_new("coroutine", func, data);
+}
+
+#else
+
+/* Handle older GLib versions */
+static GCond *coroutine_cond;
+static inline void init_coroutine_cond(void)
+{
+ coroutine_cond = g_cond_new();
+}
+
static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;
+static inline CoroutineGThread *get_coroutine_key(void)
+{
+ return g_static_private_get(&coroutine_key);
+}
+
+static inline void set_coroutine_key(CoroutineGThread *co,
+ bool free_on_thread_exit)
+{
+ g_static_private_set(&coroutine_key, co,
+ free_on_thread_exit ? (GDestroyNotify)g_free : NULL);
+}
+
+static inline GThread *create_thread(GThreadFunc func, gpointer data)
+{
+ return g_thread_create_full(func, data, 0, TRUE, TRUE,
+ G_THREAD_PRIORITY_NORMAL, NULL);
+}
+
+#endif
+
+
static void __attribute__((constructor)) coroutine_init(void)
{
if (!g_thread_supported()) {
@@ -44,7 +124,7 @@ static void __attribute__((constructor)) coroutine_init(void)
#endif
}
- coroutine_cond = g_cond_new();
+ init_coroutine_cond();
}
static void coroutine_wait_runnable_locked(CoroutineGThread *co)
@@ -65,7 +145,7 @@ static gpointer coroutine_thread(gpointer opaque)
{
CoroutineGThread *co = opaque;
- g_static_private_set(&coroutine_key, co, NULL);
+ set_coroutine_key(co, false);
coroutine_wait_runnable(co);
co->base.entry(co->base.entry_arg);
qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE);
@@ -77,8 +157,7 @@ Coroutine *qemu_coroutine_new(void)
CoroutineGThread *co;
co = g_malloc0(sizeof(*co));
- co->thread = g_thread_create_full(coroutine_thread, co, 0, TRUE, TRUE,
- G_THREAD_PRIORITY_NORMAL, NULL);
+ co->thread = create_thread(coroutine_thread, co);
if (!co->thread) {
g_free(co);
return NULL;
@@ -117,12 +196,11 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_,
Coroutine *qemu_coroutine_self(void)
{
- CoroutineGThread *co = g_static_private_get(&coroutine_key);
-
+ CoroutineGThread *co = get_coroutine_key();
if (!co) {
co = g_malloc0(sizeof(*co));
co->runnable = true;
- g_static_private_set(&coroutine_key, co, (GDestroyNotify)g_free);
+ set_coroutine_key(co, true);
}
return &co->base;
@@ -130,7 +208,7 @@ Coroutine *qemu_coroutine_self(void)
bool qemu_in_coroutine(void)
{
- CoroutineGThread *co = g_static_private_get(&coroutine_key);
+ CoroutineGThread *co = get_coroutine_key();
return co && co->base.caller;
}
commit 044c62aaf223b3b5a8eae4f5f79b210a65501e23
Merge: e92861c... e554bbc...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Apr 14 10:56:04 2012 +0000
Merge branch 'xtensa' of git://jcmvbkbc.spb.ru/dumb/qemu-xtensa
* 'xtensa' of git://jcmvbkbc.spb.ru/dumb/qemu-xtensa:
target-xtensa: Start QOM'ifying CPU init
target-xtensa: QOM'ify CPU reset
target-xtensa: QOM'ify CPU
target-xtensa: improve unit tests debugging
target-xtensa: Move helpers.h to helper.h
commit e92861ccb166883b0672b1ddfebce4f5de85e23d
Merge: 7672725... c79981c...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Apr 14 10:55:00 2012 +0000
Merge branch 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
* 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm:
hw/arm_gic: Remove stray hardcoded tab
hw/arm_gic: gic_set_pending_private() is NVIC only
hw/arm_gic: Use NVIC instead of LEGACY_INCLUDED_GIC define
hw/arm_gic: Make gic_reset a sysbus reset function
hw/arm11mpcore: Convert to using sysbus GIC device
hw/exynos4210_gic: Convert to using sysbus GIC
hw/realview_gic: switch to sysbus GIC
hw/a9mpcore: Switch to using sysbus GIC
hw/a15mpcore: switch to using sysbus GIC
hw/arm_gic: Make the GIC its own sysbus device
hw/arm_gic: Expose PPI inputs as gpio inputs
hw/arm_gic: Move gic_get_current_cpu into arm_gic.c
hw/arm_gic: Move NCPU definition to arm_gic.c
hw/exynos4210_combiner.c: Drop excessive read/write access check.
ARM: Exynos4210: Drop gic_cpu_write() after initialization.
Fix bit test in Exynos4210 UART emulation to use & instead of &&
commit e554bbc6892394e506f5995ff4e0ca21cfe04a25
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 18:24:50 2012 +0200
target-xtensa: Start QOM'ifying CPU init
Move XtensaConfig-independent code from cpu_xtensa_init() into a
QOM initfn, as a start.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index 55d2dea..97deacb 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -53,6 +53,14 @@ static void xtensa_cpu_reset(CPUState *s)
reset_mmu(env);
}
+static void xtensa_cpu_initfn(Object *obj)
+{
+ XtensaCPU *cpu = XTENSA_CPU(obj);
+ CPUXtensaState *env = &cpu->env;
+
+ cpu_exec_init(env);
+}
+
static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
@@ -66,6 +74,7 @@ static const TypeInfo xtensa_cpu_type_info = {
.name = TYPE_XTENSA_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(XtensaCPU),
+ .instance_init = xtensa_cpu_initfn,
.abstract = false,
.class_size = sizeof(XtensaCPUClass),
.class_init = xtensa_cpu_class_init,
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 000f965..2094227 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -102,7 +102,6 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU));
env = &cpu->env;
env->config = config;
- cpu_exec_init(env);
if (!tcg_inited) {
tcg_inited = 1;
commit 5087a72cb3e94f48c1d447babd67e33bfd9dda12
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 18:24:49 2012 +0200
target-xtensa: QOM'ify CPU reset
Move code from cpu_state_reset() into QOM xtensa_cpu_reset().
To avoid moving reset_mmu() and dependencies, make it non-static.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index d68be22..55d2dea 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -1,6 +1,7 @@
/*
* QEMU Xtensa CPU
*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
* Copyright (c) 2012 SUSE LINUX Products GmbH
* All rights reserved.
*
@@ -40,7 +41,16 @@ static void xtensa_cpu_reset(CPUState *s)
xcc->parent_reset(s);
- cpu_state_reset(env);
+ env->exception_taken = 0;
+ env->pc = env->config->exception_vector[EXC_RESET];
+ env->sregs[LITBASE] &= ~1;
+ env->sregs[PS] = xtensa_option_enabled(env->config,
+ XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
+ env->sregs[VECBASE] = env->config->vecbase;
+ env->sregs[IBREAKENABLE] = 0;
+
+ env->pending_irq_level = 0;
+ reset_mmu(env);
}
static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 2de5144..6d0ea7c 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -375,6 +375,7 @@ void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
int xtensa_get_physical_addr(CPUXtensaState *env,
uint32_t vaddr, int is_write, int mmu_idx,
uint32_t *paddr, uint32_t *page_size, unsigned *access);
+void reset_mmu(CPUXtensaState *env);
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env);
void debug_exception_env(CPUXtensaState *new_env, uint32_t cause);
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 20338e6..000f965 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -33,20 +33,9 @@
#include "hw/loader.h"
#endif
-static void reset_mmu(CPUXtensaState *env);
-
void cpu_state_reset(CPUXtensaState *env)
{
- env->exception_taken = 0;
- env->pc = env->config->exception_vector[EXC_RESET];
- env->sregs[LITBASE] &= ~1;
- env->sregs[PS] = xtensa_option_enabled(env->config,
- XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
- env->sregs[VECBASE] = env->config->vecbase;
- env->sregs[IBREAKENABLE] = 0;
-
- env->pending_irq_level = 0;
- reset_mmu(env);
+ cpu_reset(ENV_GET_CPU(env));
}
static struct XtensaConfigList *xtensa_cores;
@@ -336,7 +325,7 @@ static void reset_tlb_region_way0(CPUXtensaState *env,
}
}
-static void reset_mmu(CPUXtensaState *env)
+void reset_mmu(CPUXtensaState *env)
{
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
env->sregs[RASID] = 0x04030201;
commit a4633e16d77bd1cf0c25e500d15943499b94f2f9
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 18:24:48 2012 +0200
target-xtensa: QOM'ify CPU
Embed CPUXtensaState as first member of XtensaCPU.
Let CPUClass::reset() call cpu_state_reset() for now.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
diff --git a/Makefile.target b/Makefile.target
index e88b896..75b97ae 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -102,6 +102,7 @@ endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
libobj-$(TARGET_UNICORE32) += cpu.o
+libobj-$(TARGET_XTENSA) += cpu.o
libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
libobj-y += disas.o
diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h
new file mode 100644
index 0000000..1fd2f27
--- /dev/null
+++ b/target-xtensa/cpu-qom.h
@@ -0,0 +1,80 @@
+/*
+ * QEMU Xtensa CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef QEMU_XTENSA_CPU_QOM_H
+#define QEMU_XTENSA_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_XTENSA_CPU "xtensa-cpu"
+
+#define XTENSA_CPU_CLASS(class) \
+ OBJECT_CLASS_CHECK(XtensaCPUClass, (class), TYPE_XTENSA_CPU)
+#define XTENSA_CPU(obj) \
+ OBJECT_CHECK(XtensaCPU, (obj), TYPE_XTENSA_CPU)
+#define XTENSA_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XtensaCPUClass, (obj), TYPE_XTENSA_CPU)
+
+/**
+ * XtensaCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An Xtensa CPU model.
+ */
+typedef struct XtensaCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} XtensaCPUClass;
+
+/**
+ * XtensaCPU:
+ * @env: #CPUXtensaState
+ *
+ * An Xtensa CPU.
+ */
+typedef struct XtensaCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUXtensaState env;
+} XtensaCPU;
+
+static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env)
+{
+ return XTENSA_CPU(container_of(env, XtensaCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(xtensa_env_get_cpu(e))
+
+
+#endif
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
new file mode 100644
index 0000000..d68be22
--- /dev/null
+++ b/target-xtensa/cpu.c
@@ -0,0 +1,69 @@
+/*
+ * QEMU Xtensa CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+
+
+/* CPUClass::reset() */
+static void xtensa_cpu_reset(CPUState *s)
+{
+ XtensaCPU *cpu = XTENSA_CPU(s);
+ XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+ CPUXtensaState *env = &cpu->env;
+
+ xcc->parent_reset(s);
+
+ cpu_state_reset(env);
+}
+
+static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
+{
+ CPUClass *cc = CPU_CLASS(oc);
+ XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc);
+
+ xcc->parent_reset = cc->reset;
+ cc->reset = xtensa_cpu_reset;
+}
+
+static const TypeInfo xtensa_cpu_type_info = {
+ .name = TYPE_XTENSA_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(XtensaCPU),
+ .abstract = false,
+ .class_size = sizeof(XtensaCPUClass),
+ .class_init = xtensa_cpu_class_init,
+};
+
+static void xtensa_cpu_register_types(void)
+{
+ type_register_static(&xtensa_cpu_type_info);
+}
+
+type_init(xtensa_cpu_register_types)
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index a7bcf52..2de5144 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -470,6 +470,7 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
}
#include "cpu-all.h"
+#include "cpu-qom.h"
#include "exec-all.h"
static inline int cpu_has_work(CPUXtensaState *env)
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index dab135c..20338e6 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -95,6 +95,7 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
{
static int tcg_inited;
static int debug_handler_inited;
+ XtensaCPU *cpu;
CPUXtensaState *env;
const XtensaConfig *config = NULL;
XtensaConfigList *core = xtensa_cores;
@@ -109,7 +110,8 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
return NULL;
}
- env = g_malloc0(sizeof(*env));
+ cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU));
+ env = &cpu->env;
env->config = config;
cpu_exec_init(env);
commit 7d6b9f0a3838632b4c553e0a387af0bbdf4297c0
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Fri Mar 16 01:24:57 2012 +0400
target-xtensa: improve unit tests debugging
- add testcase announcement;
- add global symbols for individual tests;
- add host-debug-* makefile target.
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile
index 7e1e619..0ff0ccf 100644
--- a/tests/tcg/xtensa/Makefile
+++ b/tests/tcg/xtensa/Makefile
@@ -72,5 +72,8 @@ run-test_fail.tst: test_fail.tst
debug-%.tst: %.tst
$(SIM) $(SIMDEBUG) $(SIMFLAGS) ./$<
+host-debug-%.tst: %.tst
+ gdb --args $(SIM) $(SIMFLAGS) ./$<
+
clean:
$(RM) -fr $(TESTCASES) $(CRT)
diff --git a/tests/tcg/xtensa/macros.inc b/tests/tcg/xtensa/macros.inc
index 2d4515e..23bf3e9 100644
--- a/tests/tcg/xtensa/macros.inc
+++ b/tests/tcg/xtensa/macros.inc
@@ -29,7 +29,24 @@ main:
exit
.endm
+.macro print text
+.data
+97: .ascii "\text\n"
+98:
+ .align 4
+.text
+ movi a2, 4
+ movi a3, 2
+ movi a4, 97b
+ movi a5, 98b
+ sub a5, a5, a4
+ simcall
+.endm
+
.macro test name
+ //print test_\name
+test_\name:
+.global test_\name
.endm
.macro test_end
commit 16c1deae215d4aac5b9b4fc090844b92852a0c5b
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Mon Feb 13 16:33:58 2012 +0100
target-xtensa: Move helpers.h to helper.h
Provides a file naming scheme consistent with other targets.
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h
new file mode 100644
index 0000000..48a741e
--- /dev/null
+++ b/target-xtensa/helper.h
@@ -0,0 +1,39 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_2(exception_cause, void, i32, i32)
+DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
+DEF_HELPER_2(debug_exception, void, i32, i32)
+
+DEF_HELPER_1(nsa, i32, i32)
+DEF_HELPER_1(nsau, i32, i32)
+DEF_HELPER_1(wsr_windowbase, void, i32)
+DEF_HELPER_3(entry, void, i32, i32, i32)
+DEF_HELPER_1(retw, i32, i32)
+DEF_HELPER_1(rotw, void, i32)
+DEF_HELPER_2(window_check, void, i32, i32)
+DEF_HELPER_0(restore_owb, void)
+DEF_HELPER_1(movsp, void, i32)
+DEF_HELPER_1(wsr_lbeg, void, i32)
+DEF_HELPER_1(wsr_lend, void, i32)
+DEF_HELPER_1(simcall, void, env)
+DEF_HELPER_0(dump_state, void)
+
+DEF_HELPER_2(waiti, void, i32, i32)
+DEF_HELPER_2(timer_irq, void, i32, i32)
+DEF_HELPER_1(advance_ccount, void, i32)
+DEF_HELPER_1(check_interrupts, void, env)
+
+DEF_HELPER_1(wsr_rasid, void, i32)
+DEF_HELPER_2(rtlb0, i32, i32, i32)
+DEF_HELPER_2(rtlb1, i32, i32, i32)
+DEF_HELPER_2(itlb, void, i32, i32)
+DEF_HELPER_2(ptlb, i32, i32, i32)
+DEF_HELPER_3(wtlb, void, i32, i32, i32)
+
+DEF_HELPER_1(wsr_ibreakenable, void, i32)
+DEF_HELPER_2(wsr_ibreaka, void, i32, i32)
+DEF_HELPER_2(wsr_dbreaka, void, i32, i32)
+DEF_HELPER_2(wsr_dbreakc, void, i32, i32)
+
+#include "def-helper.h"
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
deleted file mode 100644
index 48a741e..0000000
--- a/target-xtensa/helpers.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "def-helper.h"
-
-DEF_HELPER_1(exception, void, i32)
-DEF_HELPER_2(exception_cause, void, i32, i32)
-DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
-DEF_HELPER_2(debug_exception, void, i32, i32)
-
-DEF_HELPER_1(nsa, i32, i32)
-DEF_HELPER_1(nsau, i32, i32)
-DEF_HELPER_1(wsr_windowbase, void, i32)
-DEF_HELPER_3(entry, void, i32, i32, i32)
-DEF_HELPER_1(retw, i32, i32)
-DEF_HELPER_1(rotw, void, i32)
-DEF_HELPER_2(window_check, void, i32, i32)
-DEF_HELPER_0(restore_owb, void)
-DEF_HELPER_1(movsp, void, i32)
-DEF_HELPER_1(wsr_lbeg, void, i32)
-DEF_HELPER_1(wsr_lend, void, i32)
-DEF_HELPER_1(simcall, void, env)
-DEF_HELPER_0(dump_state, void)
-
-DEF_HELPER_2(waiti, void, i32, i32)
-DEF_HELPER_2(timer_irq, void, i32, i32)
-DEF_HELPER_1(advance_ccount, void, i32)
-DEF_HELPER_1(check_interrupts, void, env)
-
-DEF_HELPER_1(wsr_rasid, void, i32)
-DEF_HELPER_2(rtlb0, i32, i32, i32)
-DEF_HELPER_2(rtlb1, i32, i32, i32)
-DEF_HELPER_2(itlb, void, i32, i32)
-DEF_HELPER_2(ptlb, i32, i32, i32)
-DEF_HELPER_3(wtlb, void, i32, i32, i32)
-
-DEF_HELPER_1(wsr_ibreakenable, void, i32)
-DEF_HELPER_2(wsr_ibreaka, void, i32, i32)
-DEF_HELPER_2(wsr_dbreaka, void, i32, i32)
-DEF_HELPER_2(wsr_dbreakc, void, i32, i32)
-
-#include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index cdef0db..806384f 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -27,7 +27,7 @@
#include "cpu.h"
#include "dyngen-exec.h"
-#include "helpers.h"
+#include "helper.h"
#include "host-utils.h"
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index e0ff72b..492dbcc 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -37,9 +37,9 @@
#include "qemu-log.h"
#include "sysemu.h"
-#include "helpers.h"
+#include "helper.h"
#define GEN_HELPER 1
-#include "helpers.h"
+#include "helper.h"
typedef struct DisasContext {
const XtensaConfig *config;
@@ -183,7 +183,7 @@ void xtensa_translate_init(void)
}
}
#define GEN_HELPER 2
-#include "helpers.h"
+#include "helper.h"
}
static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt)
diff --git a/xtensa-semi.c b/xtensa-semi.c
index 5754b77..b7c8c34 100644
--- a/xtensa-semi.c
+++ b/xtensa-semi.c
@@ -31,7 +31,7 @@
#include <stddef.h>
#include "cpu.h"
#include "dyngen-exec.h"
-#include "helpers.h"
+#include "helper.h"
#include "qemu-log.h"
enum {
commit fda1f7684935ae7290c8a31e3ba9fdb30eead4ed
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date: Fri Apr 13 17:46:01 2012 +0000
xen: introduce an event channel for buffered io event notifications
Use the newly introduced HVM_PARAM_BUFIOREQ_EVTCHN to receive
notifications for buffered io events.
After the first notification is received leave the event channel masked
and setup a timer to process the rest of the batch.
Once we have completed processing the batch, unmask the event channel
and delete the timer.
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/xen-all.c b/xen-all.c
index abd2b2d..a08eec0 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -59,6 +59,9 @@ static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
}
# define FMT_ioreq_size "u"
#endif
+#ifndef HVM_PARAM_BUFIOREQ_EVTCHN
+#define HVM_PARAM_BUFIOREQ_EVTCHN 26
+#endif
#define BUFFER_IO_MAX_DELAY 100
@@ -77,6 +80,8 @@ typedef struct XenIOState {
QEMUTimer *buffered_io_timer;
/* the evtchn port for polling the notification, */
evtchn_port_t *ioreq_local_port;
+ /* evtchn local port for buffered io */
+ evtchn_port_t bufioreq_local_port;
/* the evtchn fd for polling */
XenEvtchn xce_handle;
/* which vcpu we are serving */
@@ -629,6 +634,12 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state)
evtchn_port_t port;
port = xc_evtchn_pending(state->xce_handle);
+ if (port == state->bufioreq_local_port) {
+ qemu_mod_timer(state->buffered_io_timer,
+ BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+ return NULL;
+ }
+
if (port != -1) {
for (i = 0; i < smp_cpus; i++) {
if (state->ioreq_local_port[i] == port) {
@@ -777,16 +788,18 @@ static void handle_ioreq(ioreq_t *req)
}
}
-static void handle_buffered_iopage(XenIOState *state)
+static int handle_buffered_iopage(XenIOState *state)
{
buf_ioreq_t *buf_req = NULL;
ioreq_t req;
int qw;
if (!state->buffered_io_page) {
- return;
+ return 0;
}
+ memset(&req, 0x00, sizeof(req));
+
while (state->buffered_io_page->read_pointer != state->buffered_io_page->write_pointer) {
buf_req = &state->buffered_io_page->buf_ioreq[
state->buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
@@ -811,15 +824,21 @@ static void handle_buffered_iopage(XenIOState *state)
xen_mb();
state->buffered_io_page->read_pointer += qw ? 2 : 1;
}
+
+ return req.count;
}
static void handle_buffered_io(void *opaque)
{
XenIOState *state = opaque;
- handle_buffered_iopage(state);
- qemu_mod_timer(state->buffered_io_timer,
- BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+ if (handle_buffered_iopage(state)) {
+ qemu_mod_timer(state->buffered_io_timer,
+ BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+ } else {
+ qemu_del_timer(state->buffered_io_timer);
+ xc_evtchn_unmask(state->xce_handle, state->bufioreq_local_port);
+ }
}
static void cpu_handle_ioreq(void *opaque)
@@ -949,7 +968,6 @@ static void xen_main_loop_prepare(XenIOState *state)
state->buffered_io_timer = qemu_new_timer_ms(rt_clock, handle_buffered_io,
state);
- qemu_mod_timer(state->buffered_io_timer, qemu_get_clock_ms(rt_clock));
if (evtchn_fd != -1) {
qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state);
@@ -1050,6 +1068,7 @@ int xen_hvm_init(void)
{
int i, rc;
unsigned long ioreq_pfn;
+ unsigned long bufioreq_evtchn;
XenIOState *state;
state = g_malloc0(sizeof (XenIOState));
@@ -1102,6 +1121,20 @@ int xen_hvm_init(void)
state->ioreq_local_port[i] = rc;
}
+ rc = xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_EVTCHN,
+ &bufioreq_evtchn);
+ if (rc < 0) {
+ fprintf(stderr, "failed to get HVM_PARAM_BUFIOREQ_EVTCHN\n");
+ return -1;
+ }
+ rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid,
+ (uint32_t)bufioreq_evtchn);
+ if (rc == -1) {
+ fprintf(stderr, "bind interdomain ioctl error %d\n", errno);
+ return -1;
+ }
+ state->bufioreq_local_port = rc;
+
/* Init RAM management */
xen_map_cache_init(xen_phys_offset_to_gaddr, state);
xen_ram_init(ram_size);
commit 852a7cec90f12516eb335bb29ed1398c2f0b7c2c
Author: Julien Grall <julien.grall at citrix.com>
Date: Fri Apr 13 17:33:02 2012 +0000
xen-mapcache: don't unmap locked entry during mapcache invalidation
When an IOREQ_TYPE_INVALIDATE is sent to QEMU, it invalidates all entry
of the map cache even if it's locked.
QEMU is not able to know that entry was invalidated, so when an IO
access is requested a segfault occured.
Signed-off-by: Julien Grall <julien.grall at citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/xen-mapcache.c b/xen-mapcache.c
index 75ac313..59ba085 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -387,6 +387,9 @@ void xen_invalidate_map_cache(void)
if (entry->vaddr_base == NULL) {
continue;
}
+ if (entry->lock > 0) {
+ continue;
+ }
if (munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
commit 09ab48ee6c7ec082f56f85e234b066ed4fd874e2
Author: Anthony PERARD <anthony.perard at citrix.com>
Date: Fri Apr 13 17:18:56 2012 +0000
Xen, mapcache: Fix the compute of the size of bucket.
Because the size of a mapping is wrong when there is an offset and a
size >= bucket_size.
Signed-off-by: Anthony PERARD <anthony.perard at citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/xen-mapcache.c b/xen-mapcache.c
index a456479..75ac313 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -216,12 +216,14 @@ tryagain:
}
/* size is always a multiple of MCACHE_BUCKET_SIZE */
- if ((address_offset + (__size % MCACHE_BUCKET_SIZE)) > MCACHE_BUCKET_SIZE)
- __size += MCACHE_BUCKET_SIZE;
- if (__size % MCACHE_BUCKET_SIZE)
- __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE);
- if (!__size)
+ if (size) {
+ __size = size + address_offset;
+ if (__size % MCACHE_BUCKET_SIZE) {
+ __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE);
+ }
+ } else {
__size = MCACHE_BUCKET_SIZE;
+ }
entry = &mapcache->entry[address_index % mapcache->nr_buckets];
commit 77ba8fef8972854b7fad89d97a14f4f9c3eae7a8
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date: Fri Mar 30 14:33:03 2012 +0000
xen: handle backend deletion from xenstore
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index 2673ace..66cb144 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -592,7 +592,7 @@ static void xenstore_update_be(char *watch, char *type, int dom,
struct XenDevOps *ops)
{
struct XenDevice *xendev;
- char path[XEN_BUFSIZE], *dom0;
+ char path[XEN_BUFSIZE], *dom0, *bepath;
unsigned int len, dev;
dom0 = xs_get_domain_path(xenstore, 0);
@@ -611,15 +611,16 @@ static void xenstore_update_be(char *watch, char *type, int dom,
return;
}
- if (0) {
- /* FIXME: detect devices being deleted from xenstore ... */
- xen_be_del_xendev(dom, dev);
- }
-
xendev = xen_be_get_xendev(type, dom, dev, ops);
if (xendev != NULL) {
- xen_be_backend_changed(xendev, path);
- xen_be_check_state(xendev);
+ bepath = xs_read(xenstore, 0, xendev->be, &len);
+ if (bepath == NULL) {
+ xen_be_del_xendev(dom, dev);
+ } else {
+ free(bepath);
+ xen_be_backend_changed(xendev, path);
+ xen_be_check_state(xendev);
+ }
}
}
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 9719395..22dbd10 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -745,6 +745,10 @@ static int blk_free(struct XenDevice *xendev)
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
struct ioreq *ioreq;
+ if (blkdev->bs || blkdev->sring) {
+ blk_disconnect(xendev);
+ }
+
while (!QLIST_EMPTY(&blkdev->freelist)) {
ioreq = QLIST_FIRST(&blkdev->freelist);
QLIST_REMOVE(ioreq, list);
commit 9468e9c41a89b1c9f3a905b8959e1dd3f055c732
Author: Wei Liu <wei.liu2 at citrix.com>
Date: Thu Apr 12 10:02:47 2012 +0000
Xen: Add xen-apic support and hook it up.
Signed-off-by: Wei Liu <wei.liu2 at citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Acked-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/Makefile.target b/Makefile.target
index e88b896..f9ce361 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -237,7 +237,7 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o
obj-$(CONFIG_NO_XEN) += xen-stub.o
-obj-i386-$(CONFIG_XEN) += xen_platform.o
+obj-i386-$(CONFIG_XEN) += xen_platform.o xen_apic.o
# Inter-VM PCI shared memory
CONFIG_IVSHMEM =
diff --git a/hw/pc.c b/hw/pc.c
index 67f0479..1f5aacb 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -42,6 +42,7 @@
#include "sysbus.h"
#include "sysemu.h"
#include "kvm.h"
+#include "xen.h"
#include "blockdev.h"
#include "ui/qemu-spice.h"
#include "memory.h"
@@ -891,9 +892,12 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
if (kvm_irqchip_in_kernel()) {
dev = qdev_create(NULL, "kvm-apic");
+ } else if (xen_enabled()) {
+ dev = qdev_create(NULL, "xen-apic");
} else {
dev = qdev_create(NULL, "apic");
}
+
qdev_prop_set_uint8(dev, "id", apic_id);
qdev_prop_set_ptr(dev, "cpu_env", env);
qdev_init_nofail(dev);
@@ -912,6 +916,10 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
msi_supported = true;
}
+ if (xen_enabled()) {
+ msi_supported = true;
+ }
+
return dev;
}
diff --git a/hw/xen_apic.c b/hw/xen_apic.c
new file mode 100644
index 0000000..1725ff6
--- /dev/null
+++ b/hw/xen_apic.c
@@ -0,0 +1,90 @@
+/*
+ * Xen basic APIC support
+ *
+ * Copyright (c) 2012 Citrix
+ *
+ * Authors:
+ * Wei Liu <wei.liu2 at citrix.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+#include "hw/apic_internal.h"
+#include "hw/msi.h"
+#include "xen.h"
+
+static uint64_t xen_apic_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ return ~(uint64_t)0;
+}
+
+static void xen_apic_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t data, unsigned size)
+{
+ if (size != sizeof(uint32_t)) {
+ fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size);
+ return;
+ }
+
+ xen_hvm_inject_msi(addr, data);
+}
+
+static const MemoryRegionOps xen_apic_io_ops = {
+ .read = xen_apic_mem_read,
+ .write = xen_apic_mem_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void xen_apic_init(APICCommonState *s)
+{
+ memory_region_init_io(&s->io_memory, &xen_apic_io_ops, s, "xen-apic-msi",
+ MSI_SPACE_SIZE);
+}
+
+static void xen_apic_set_base(APICCommonState *s, uint64_t val)
+{
+}
+
+static void xen_apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+}
+
+static uint8_t xen_apic_get_tpr(APICCommonState *s)
+{
+ return 0;
+}
+
+static void xen_apic_vapic_base_update(APICCommonState *s)
+{
+}
+
+static void xen_apic_external_nmi(APICCommonState *s)
+{
+}
+
+static void xen_apic_class_init(ObjectClass *klass, void *data)
+{
+ APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+ k->init = xen_apic_init;
+ k->set_base = xen_apic_set_base;
+ k->set_tpr = xen_apic_set_tpr;
+ k->get_tpr = xen_apic_get_tpr;
+ k->vapic_base_update = xen_apic_vapic_base_update;
+ k->external_nmi = xen_apic_external_nmi;
+}
+
+static TypeInfo xen_apic_info = {
+ .name = "xen-apic",
+ .parent = TYPE_APIC_COMMON,
+ .instance_size = sizeof(APICCommonState),
+ .class_init = xen_apic_class_init,
+};
+
+static void xen_apic_register_types(void)
+{
+ type_register_static(&xen_apic_info);
+}
+
+type_init(xen_apic_register_types)
commit f1dbf015dfb0aa7f66f710a1f1bc58b662951de2
Author: Wei Liu <wei.liu2 at citrix.com>
Date: Thu Apr 12 10:01:43 2012 +0000
Xen: basic HVM MSI injection support.
Signed-off-by: Wei Liu <wei.liu2 at citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/hw/xen.h b/hw/xen.h
index b46879c..e5926b7 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -34,6 +34,7 @@ static inline int xen_enabled(void)
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
void xen_piix3_set_irq(void *opaque, int irq_num, int level);
void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
+void xen_hvm_inject_msi(uint64_t addr, uint32_t data);
void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
qemu_irq *xen_interrupt_controller_init(void);
diff --git a/xen-all.c b/xen-all.c
index 3e6de41..abd2b2d 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -122,6 +122,11 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
}
}
+void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
+{
+ xc_hvm_inject_msi(xen_xc, xen_domid, addr, data);
+}
+
static void xen_suspend_notifier(Notifier *notifier, void *data)
{
xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
diff --git a/xen-stub.c b/xen-stub.c
index 9ea02d4..8ff2b79 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -29,6 +29,10 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
{
}
+void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
+{
+}
+
void xen_cmos_set_s3_resume(void *opaque, int irq, int level)
{
}
commit 7672725d41d1a04195affc1a7bd5676ba6314b14
Merge: 3cbe19b... 6ccea1e...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Fri Apr 13 08:04:43 2012 -0500
Merge remote-tracking branch 'stefanha/trivial-patches' into staging
* stefanha/trivial-patches:
configure: Insist on a Python 2, not Python 3
bsd-user: fix compile failure
ps2: avoid repeated header file includes
make: Always set LC_ALL=C for makeinfo
configure: Fix wrong preprocessor statement
configure: Remove useless uses of ARCH_CFLAGS
commit 3cbe19b2e27238caa8b7518182eb674b8169b8df
Merge: a602e48... f349c12...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Fri Apr 13 08:04:31 2012 -0500
Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
* qemu-kvm/uq/master:
kvmclock: guest stop notification
kvm: update linux headers
kvm: set gsi_bits and max_gsi correctly
kvm: Drop unused kvm_pit_in_kernel
kvm: allow arbitrarily sized mmio ioeventfd
kvm: Drop redundant kvm_enabled from cpu_thread_is_idle
kvm: add flightrecorder script
commit a602e48958eb70b33415407e6f64bc883e019c37
Merge: dadc106... 3eab169...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Fri Apr 13 08:04:13 2012 -0500
Merge remote-tracking branch 'afaerber/qom-cpu-lm32.v3' into staging
* afaerber/qom-cpu-lm32.v3:
target-lm32: QOM'ify CPU reset
target-lm32: QOM'ify CPU init
target-lm32: QOM'ify CPU
commit c79981ceec3ae1e712aa9c21cba94c152eea2fb5
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:09 2012 +0000
hw/arm_gic: Remove stray hardcoded tab
Remove the single instance of a hardcoded tab from hw/arm_gic.c.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index ba6117a..72298b4 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -160,7 +160,7 @@ static void gic_update(gic_state *s)
cm = 1 << cpu;
s->current_pending[cpu] = 1023;
if (!s->enabled || !s->cpu_enabled[cpu]) {
- qemu_irq_lower(s->parent_irq[cpu]);
+ qemu_irq_lower(s->parent_irq[cpu]);
return;
}
best_prio = 0x100;
commit b7dc1a597ab2d755c135852ce22d98fa00ab414f
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:09 2012 +0000
hw/arm_gic: gic_set_pending_private() is NVIC only
The function gic_set_pending_private() is now used by the NVIC
only (for the GIC we now set PPI interrupts via gpio lines and
gic_set_irq()). So make it #ifdef NVIC and remove the 'attribute
unused' annotation.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 589ac5e..ba6117a 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -185,8 +185,8 @@ static void gic_update(gic_state *s)
}
}
-static void __attribute__((unused))
-gic_set_pending_private(gic_state *s, int cpu, int irq)
+#ifdef NVIC
+static void gic_set_pending_private(gic_state *s, int cpu, int irq)
{
int cm = 1 << cpu;
@@ -197,6 +197,7 @@ gic_set_pending_private(gic_state *s, int cpu, int irq)
GIC_SET_PENDING(irq, cm);
gic_update(s);
}
+#endif
/* Process a change in an external IRQ input. */
static void gic_set_irq(void *opaque, int irq, int level)
commit 0d256bdc8f540a52fe1f0475aeeed3bc9f6e2de4
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:09 2012 +0000
hw/arm_gic: Use NVIC instead of LEGACY_INCLUDED_GIC define
Now all the A profile cores have been switched to use the standalone
sysbus GIC, the only remaining code which #includes arm_gic.c is
the v7M NVIC. The coupling is much closer here so it's not so
easily disentangled. For now, add a comment about how arm_gic.c
is compiled, and assume that the NVIC always includes arm_gic.c
and the non-NVIC GIC is always compiled standalone.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 81858c3..589ac5e 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -8,8 +8,15 @@
*/
/* This file contains implementation code for the RealView EB interrupt
- controller, MPCore distributed interrupt controller and ARMv7-M
- Nested Vectored Interrupt Controller. */
+ * controller, MPCore distributed interrupt controller and ARMv7-M
+ * Nested Vectored Interrupt Controller.
+ * It is compiled in two ways:
+ * (1) as a standalone file to produce a sysbus device which is a GIC
+ * that can be used on the realview board and as one of the builtin
+ * private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
+ * (2) by being directly #included into armv7m_nvic.c to produce the
+ * armv7m_nvic device.
+ */
#include "sysbus.h"
@@ -909,7 +916,7 @@ static void gic_init(gic_state *s, int num_irq)
register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
}
-#ifndef LEGACY_INCLUDED_GIC
+#ifndef NVIC
static int arm_gic_init(SysBusDevice *dev)
{
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 5cfa971..986a6bb 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -16,7 +16,6 @@
#include "exec-memory.h"
#define NVIC 1
-#define LEGACY_INCLUDED_GIC
static uint32_t nvic_readl(void *opaque, uint32_t offset);
static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
commit aecff6924dab0197b6c8f132e44502b25fd98a38
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:09 2012 +0000
hw/arm_gic: Make gic_reset a sysbus reset function
Make gic_reset a sysbus reset function, so we actually
reset the GIC on system reset rather than only at init.
For the NVIC this requires us also to implement reset
of the SysTick.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index b543570..81858c3 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -741,8 +741,9 @@ static const MemoryRegionOps gic_cpu_ops = {
};
#endif
-static void gic_reset(gic_state *s)
+static void gic_reset(DeviceState *dev)
{
+ gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev));
int i;
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
for (i = 0 ; i < NUM_CPU(s); i++) {
@@ -905,7 +906,6 @@ static void gic_init(gic_state *s, int num_irq)
}
#endif
- gic_reset(s);
register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
}
@@ -938,6 +938,7 @@ static void arm_gic_class_init(ObjectClass *klass, void *data)
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
sbc->init = arm_gic_init;
dc->props = arm_gic_properties;
+ dc->reset = gic_reset;
dc->no_user = 1;
}
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 79cf448..5cfa971 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -76,6 +76,14 @@ static void systick_timer_tick(void * opaque)
}
}
+static void systick_reset(nvic_state *s)
+{
+ s->systick.control = 0;
+ s->systick.reload = 0;
+ s->systick.tick = 0;
+ qemu_del_timer(s->systick.timer);
+}
+
/* The external routines use the hardware vector numbering, ie. the first
IRQ is #16. The internal GIC routines use #32 as the first IRQ. */
void armv7m_nvic_set_pending(void *opaque, int irq)
@@ -371,6 +379,13 @@ static const VMStateDescription vmstate_nvic = {
}
};
+static void armv7m_nvic_reset(DeviceState *dev)
+{
+ nvic_state *s = FROM_SYSBUSGIC(nvic_state, sysbus_from_qdev(dev));
+ gic_reset(&s->gic.busdev.qdev);
+ systick_reset(s);
+}
+
static int armv7m_nvic_init(SysBusDevice *dev)
{
nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
@@ -400,6 +415,7 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
sdc->init = armv7m_nvic_init;
dc->vmsd = &vmstate_nvic;
+ dc->reset = armv7m_nvic_reset;
dc->props = armv7m_nvic_properties;
}
commit 2e9dfe20a62d93f145ea12a1b4755bb9cd61c327
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:08 2012 +0000
hw/arm11mpcore: Convert to using sysbus GIC device
Convert arm11mpcore to using the standalone sysbus GIC device.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index e876a0e..c528d7a 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,21 +10,18 @@
#include "sysbus.h"
#include "qemu-timer.h"
-#define LEGACY_INCLUDED_GIC
-#include "arm_gic.c"
-
/* MPCore private memory region. */
typedef struct mpcore_priv_state {
- gic_state gic;
+ SysBusDevice busdev;
uint32_t scu_control;
int iomemtype;
uint32_t old_timer_status[8];
uint32_t num_cpu;
- qemu_irq *timer_irq;
MemoryRegion iomem;
MemoryRegion container;
DeviceState *mptimer;
+ DeviceState *gic;
uint32_t num_irq;
} mpcore_priv_state;
@@ -74,18 +71,16 @@ static const MemoryRegionOps mpcore_scu_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
+static void mpcore_priv_set_irq(void *opaque, int irq, int level)
{
mpcore_priv_state *s = (mpcore_priv_state *)opaque;
- if (level && !s->old_timer_status[irq]) {
- gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
- }
- s->old_timer_status[irq] = level;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
}
static void mpcore_priv_map_setup(mpcore_priv_state *s)
{
int i;
+ SysBusDevice *gicbusdev = sysbus_from_qdev(s->gic);
SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
@@ -95,31 +90,47 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s)
*/
for (i = 0; i < (s->num_cpu + 1); i++) {
target_phys_addr_t offset = 0x100 + (i * 0x100);
- memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
+ memory_region_add_subregion(&s->container, offset,
+ sysbus_mmio_get_region(gicbusdev, i + 1));
}
/* Add the regions for timer and watchdog for "current CPU" and
* for each specific CPU.
*/
- s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
- s, (s->num_cpu + 1) * 2);
for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
/* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
memory_region_add_subregion(&s->container, offset,
sysbus_mmio_get_region(busdev, i));
}
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
- /* Wire up the interrupt from each watchdog and timer. */
- for (i = 0; i < s->num_cpu * 2; i++) {
- sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+ memory_region_add_subregion(&s->container, 0x1000,
+ sysbus_mmio_get_region(gicbusdev, 0));
+ /* Wire up the interrupt from each watchdog and timer.
+ * For each core the timer is PPI 29 and the watchdog PPI 30.
+ */
+ for (i = 0; i < s->num_cpu; i++) {
+ int ppibase = (s->num_irq - 32) + i * 32;
+ sysbus_connect_irq(busdev, i * 2,
+ qdev_get_gpio_in(s->gic, ppibase + 29));
+ sysbus_connect_irq(busdev, i * 2 + 1,
+ qdev_get_gpio_in(s->gic, ppibase + 30));
}
}
static int mpcore_priv_init(SysBusDevice *dev)
{
- mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
+ mpcore_priv_state *s = FROM_SYSBUS(mpcore_priv_state, dev);
+
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+ qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+ qdev_init_nofail(s->gic);
+
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, sysbus_from_qdev(s->gic));
+
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32);
- gic_init(&s->gic, s->num_cpu, s->num_irq);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
qdev_init_nofail(s->mptimer);
commit 23b92f60280fd250fbe421727ecfe15676d9f6ca
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:08 2012 +0000
hw/exynos4210_gic: Convert to using sysbus GIC
Convert the Exynos GIC code to use the standalone sysbus
GIC device.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Evgeny Voevodin <e.voevodin at samsung.com>
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
index a05dab2..e1b215e 100644
--- a/hw/exynos4210_gic.c
+++ b/hw/exynos4210_gic.c
@@ -262,28 +262,44 @@ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
/********* GIC part *********/
-#define LEGACY_INCLUDED_GIC
-#include "arm_gic.c"
-
typedef struct {
- gic_state gic;
+ SysBusDevice busdev;
MemoryRegion cpu_container;
MemoryRegion dist_container;
MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
MemoryRegion dist_alias[EXYNOS4210_NCPUS];
uint32_t num_cpu;
+ DeviceState *gic;
} Exynos4210GicState;
+static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
+{
+ Exynos4210GicState *s = (Exynos4210GicState *)opaque;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
static int exynos4210_gic_init(SysBusDevice *dev)
{
- Exynos4210GicState *s = FROM_SYSBUSGIC(Exynos4210GicState, dev);
+ Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev);
uint32_t i;
const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
const char dist_prefix[] = "exynos4210-gic-alias_dist";
char cpu_alias_name[sizeof(cpu_prefix) + 3];
char dist_alias_name[sizeof(cpu_prefix) + 3];
+ SysBusDevice *busdev;
+
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+ qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
+ qdev_init_nofail(s->gic);
+ busdev = sysbus_from_qdev(s->gic);
+
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, busdev);
- gic_init(&s->gic, s->num_cpu, EXYNOS4210_GIC_NIRQ);
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq,
+ EXYNOS4210_GIC_NIRQ - 32);
memory_region_init(&s->cpu_container, "exynos4210-cpu-container",
EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
@@ -295,7 +311,7 @@ static int exynos4210_gic_init(SysBusDevice *dev)
sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
memory_region_init_alias(&s->cpu_alias[i],
cpu_alias_name,
- &s->gic.cpuiomem[0],
+ sysbus_mmio_get_region(busdev, 1),
0,
EXYNOS4210_GIC_CPU_REGION_SIZE);
memory_region_add_subregion(&s->cpu_container,
@@ -305,7 +321,7 @@ static int exynos4210_gic_init(SysBusDevice *dev)
sprintf(dist_alias_name, "%s%x", dist_prefix, i);
memory_region_init_alias(&s->dist_alias[i],
dist_alias_name,
- &s->gic.iomem,
+ sysbus_mmio_get_region(busdev, 0),
0,
EXYNOS4210_GIC_DIST_REGION_SIZE);
memory_region_add_subregion(&s->dist_container,
commit fbbd05dc2ad0965d3ffd7556b8af8a74b156f9f9
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:08 2012 +0000
hw/realview_gic: switch to sysbus GIC
Switch the realview_gic device to the standalone sysbus GIC.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index a3b5a04..5bc37a7 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,31 +9,45 @@
#include "sysbus.h"
-#define LEGACY_INCLUDED_GIC
-#include "arm_gic.c"
-
typedef struct {
- gic_state gic;
+ SysBusDevice busdev;
+ DeviceState *gic;
MemoryRegion container;
} RealViewGICState;
-static void realview_gic_map_setup(RealViewGICState *s)
+static void realview_gic_set_irq(void *opaque, int irq, int level)
{
- memory_region_init(&s->container, "realview-gic-container", 0x2000);
- memory_region_add_subregion(&s->container, 0, &s->gic.cpuiomem[0]);
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+ RealViewGICState *s = (RealViewGICState *)opaque;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
}
static int realview_gic_init(SysBusDevice *dev)
{
- RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
-
+ RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev);
+ SysBusDevice *busdev;
/* The GICs on the RealView boards have a fixed nonconfigurable
* number of interrupt lines, so we don't need to expose this as
* a qdev property.
*/
- gic_init(&s->gic, 1, 96);
- realview_gic_map_setup(s);
+ int numirq = 96;
+
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", 1);
+ qdev_prop_set_uint32(s->gic, "num-irq", numirq);
+ qdev_init_nofail(s->gic);
+ busdev = sysbus_from_qdev(s->gic);
+
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, busdev);
+
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32);
+
+ memory_region_init(&s->container, "realview-gic-container", 0x2000);
+ memory_region_add_subregion(&s->container, 0,
+ sysbus_mmio_get_region(busdev, 1));
+ memory_region_add_subregion(&s->container, 0x1000,
+ sysbus_mmio_get_region(busdev, 0));
sysbus_init_mmio(dev, &s->container);
return 0;
}
commit ddd761653b14ffde7ee18d31f0350429f0402ab4
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:08 2012 +0000
hw/a9mpcore: Switch to using sysbus GIC
Switch the a9mpcore to using the sysbus GIC device rather
than having the a9mp private memory region device subclass
the GIC.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 164a0d3..c2ff74d 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -10,22 +10,19 @@
#include "sysbus.h"
-#define LEGACY_INCLUDED_GIC
-#include "arm_gic.c"
-
/* A9MP private memory region. */
typedef struct a9mp_priv_state {
- gic_state gic;
+ SysBusDevice busdev;
uint32_t scu_control;
uint32_t scu_status;
uint32_t old_timer_status[8];
uint32_t num_cpu;
- qemu_irq *timer_irq;
MemoryRegion scu_iomem;
MemoryRegion ptimer_iomem;
MemoryRegion container;
DeviceState *mptimer;
+ DeviceState *gic;
uint32_t num_irq;
} a9mp_priv_state;
@@ -114,18 +111,9 @@ static const MemoryRegionOps a9_scu_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void a9mpcore_timer_irq_handler(void *opaque, int irq, int level)
-{
- a9mp_priv_state *s = (a9mp_priv_state *)opaque;
- if (level && !s->old_timer_status[irq]) {
- gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
- }
- s->old_timer_status[irq] = level;
-}
-
static void a9mp_priv_reset(DeviceState *dev)
{
- a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, sysbus_from_qdev(dev));
+ a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, sysbus_from_qdev(dev));
int i;
s->scu_control = 0;
for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) {
@@ -133,13 +121,29 @@ static void a9mp_priv_reset(DeviceState *dev)
}
}
+static void a9mp_priv_set_irq(void *opaque, int irq, int level)
+{
+ a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
static int a9mp_priv_init(SysBusDevice *dev)
{
- a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, dev);
- SysBusDevice *busdev;
+ a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, dev);
+ SysBusDevice *busdev, *gicbusdev;
int i;
- gic_init(&s->gic, s->num_cpu, s->num_irq);
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+ qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+ qdev_init_nofail(s->gic);
+ gicbusdev = sysbus_from_qdev(s->gic);
+
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, gicbusdev);
+
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
@@ -161,7 +165,8 @@ static int a9mp_priv_init(SysBusDevice *dev)
memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100);
memory_region_add_subregion(&s->container, 0, &s->scu_iomem);
/* GIC CPU interface */
- memory_region_add_subregion(&s->container, 0x100, &s->gic.cpuiomem[0]);
+ memory_region_add_subregion(&s->container, 0x100,
+ sysbus_mmio_get_region(gicbusdev, 1));
/* Note that the A9 exposes only the "timer/watchdog for this core"
* memory region, not the "timer/watchdog for core X" ones 11MPcore has.
*/
@@ -169,15 +174,20 @@ static int a9mp_priv_init(SysBusDevice *dev)
sysbus_mmio_get_region(busdev, 0));
memory_region_add_subregion(&s->container, 0x620,
sysbus_mmio_get_region(busdev, 1));
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+ memory_region_add_subregion(&s->container, 0x1000,
+ sysbus_mmio_get_region(gicbusdev, 0));
sysbus_init_mmio(dev, &s->container);
- /* Wire up the interrupt from each watchdog and timer. */
- s->timer_irq = qemu_allocate_irqs(a9mpcore_timer_irq_handler,
- s, (s->num_cpu + 1) * 2);
- for (i = 0; i < s->num_cpu * 2; i++) {
- sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+ /* Wire up the interrupt from each watchdog and timer.
+ * For each core the timer is PPI 29 and the watchdog PPI 30.
+ */
+ for (i = 0; i < s->num_cpu; i++) {
+ int ppibase = (s->num_irq - 32) + i * 32;
+ sysbus_connect_irq(busdev, i * 2,
+ qdev_get_gpio_in(s->gic, ppibase + 29));
+ sysbus_connect_irq(busdev, i * 2 + 1,
+ qdev_get_gpio_in(s->gic, ppibase + 30));
}
return 0;
}
commit 4637a02752f29f1b28c4a4ddb0c168d2d1299227
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:07 2012 +0000
hw/a15mpcore: switch to using sysbus GIC
Switch the a15mpcore private peripheral region to using
the standalone sysbus GIC device.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
index 54c0dbf..5a7b365 100644
--- a/hw/a15mpcore.c
+++ b/hw/a15mpcore.c
@@ -20,23 +20,38 @@
#include "sysbus.h"
-#define LEGACY_INCLUDED_GIC
-#include "arm_gic.c"
-
/* A15MP private memory region. */
typedef struct A15MPPrivState {
- gic_state gic;
+ SysBusDevice busdev;
uint32_t num_cpu;
uint32_t num_irq;
MemoryRegion container;
+ DeviceState *gic;
} A15MPPrivState;
+static void a15mp_priv_set_irq(void *opaque, int irq, int level)
+{
+ A15MPPrivState *s = (A15MPPrivState *)opaque;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
static int a15mp_priv_init(SysBusDevice *dev)
{
- A15MPPrivState *s = FROM_SYSBUSGIC(A15MPPrivState, dev);
+ A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
+ SysBusDevice *busdev;
+
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+ qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+ qdev_init_nofail(s->gic);
+ busdev = sysbus_from_qdev(s->gic);
+
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, busdev);
- gic_init(&s->gic, s->num_cpu, s->num_irq);
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, a15mp_priv_set_irq, s->num_irq - 32);
/* Memory map (addresses are offsets from PERIPHBASE):
* 0x0000-0x0fff -- reserved
@@ -47,8 +62,10 @@ static int a15mp_priv_init(SysBusDevice *dev)
* 0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
*/
memory_region_init(&s->container, "a15mp-priv-container", 0x8000);
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
- memory_region_add_subregion(&s->container, 0x2000, &s->gic.cpuiomem[0]);
+ memory_region_add_subregion(&s->container, 0x1000,
+ sysbus_mmio_get_region(busdev, 0));
+ memory_region_add_subregion(&s->container, 0x2000,
+ sysbus_mmio_get_region(busdev, 1));
sysbus_init_mmio(dev, &s->container);
return 0;
@@ -72,7 +89,7 @@ static void a15mp_priv_class_init(ObjectClass *klass, void *data)
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
k->init = a15mp_priv_init;
dc->props = a15mp_priv_properties;
- /* We currently have no savable state outside the common GIC state */
+ /* We currently have no savable state */
}
static TypeInfo a15mp_priv_info = {
commit 496dbcd1a38c2ae4ada848445e4a1aa758af9f43
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:07 2012 +0000
hw/arm_gic: Make the GIC its own sysbus device
Compile arm_gic.c as a standalone C file to produce a self contained
sysbus GIC device. Support the legacy usage by #include of the .c file
by making those users #define LEGACY_INCLUDED_GIC, so we can convert
them one by one.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Evgeny Voevodin <e.voevodin at samsung.com>
diff --git a/Makefile.target b/Makefile.target
index 1110796..0f09180 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -365,6 +365,7 @@ obj-arm-y += cadence_uart.o
obj-arm-y += cadence_ttc.o
obj-arm-y += cadence_gem.o
obj-arm-y += xilinx_zynq.o zynq_slcr.o
+obj-arm-y += arm_gic.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
index 2e2ed42..54c0dbf 100644
--- a/hw/a15mpcore.c
+++ b/hw/a15mpcore.c
@@ -20,6 +20,7 @@
#include "sysbus.h"
+#define LEGACY_INCLUDED_GIC
#include "arm_gic.c"
/* A15MP private memory region. */
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 1d83c37..164a0d3 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -10,6 +10,7 @@
#include "sysbus.h"
+#define LEGACY_INCLUDED_GIC
#include "arm_gic.c"
/* A9MP private memory region. */
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index c4829d8..e876a0e 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,6 +10,7 @@
#include "sysbus.h"
#include "qemu-timer.h"
+#define LEGACY_INCLUDED_GIC
#include "arm_gic.c"
/* MPCore private memory region. */
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index fabbcc5..b543570 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -11,6 +11,8 @@
controller, MPCore distributed interrupt controller and ARMv7-M
Nested Vectored Interrupt Controller. */
+#include "sysbus.h"
+
/* Maximum number of possible interrupts, determined by the GIC architecture */
#define GIC_MAXIRQ 1020
/* First 32 are private to each CPU (SGIs and PPIs). */
@@ -112,7 +114,7 @@ typedef struct gic_state
int current_pending[NCPU];
#if NCPU > 1
- int num_cpu;
+ uint32_t num_cpu;
#endif
MemoryRegion iomem; /* Distributor */
@@ -906,3 +908,51 @@ static void gic_init(gic_state *s, int num_irq)
gic_reset(s);
register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
}
+
+#ifndef LEGACY_INCLUDED_GIC
+
+static int arm_gic_init(SysBusDevice *dev)
+{
+ /* Device instance init function for the GIC sysbus device */
+ int i;
+ gic_state *s = FROM_SYSBUS(gic_state, dev);
+ gic_init(s, s->num_cpu, s->num_irq);
+ /* Distributor */
+ sysbus_init_mmio(dev, &s->iomem);
+ /* cpu interfaces (one for "current cpu" plus one per cpu) */
+ for (i = 0; i <= NUM_CPU(s); i++) {
+ sysbus_init_mmio(dev, &s->cpuiomem[i]);
+ }
+ return 0;
+}
+
+static Property arm_gic_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1),
+ DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_gic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ sbc->init = arm_gic_init;
+ dc->props = arm_gic_properties;
+ dc->no_user = 1;
+}
+
+static TypeInfo arm_gic_info = {
+ .name = "arm_gic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(gic_state),
+ .class_init = arm_gic_class_init,
+};
+
+static void arm_gic_register_types(void)
+{
+ type_register_static(&arm_gic_info);
+}
+
+type_init(arm_gic_register_types)
+
+#endif
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 99ed85b..79cf448 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -16,6 +16,7 @@
#include "exec-memory.h"
#define NVIC 1
+#define LEGACY_INCLUDED_GIC
static uint32_t nvic_readl(void *opaque, uint32_t offset);
static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
index ff7ab84..a05dab2 100644
--- a/hw/exynos4210_gic.c
+++ b/hw/exynos4210_gic.c
@@ -262,6 +262,7 @@ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
/********* GIC part *********/
+#define LEGACY_INCLUDED_GIC
#include "arm_gic.c"
typedef struct {
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index aa780fe..a3b5a04 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,6 +9,7 @@
#include "sysbus.h"
+#define LEGACY_INCLUDED_GIC
#include "arm_gic.c"
typedef struct {
commit 544d1afa7013fce155f5afbbc24737f2fc0c0f26
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:07 2012 +0000
hw/arm_gic: Expose PPI inputs as gpio inputs
Expose the Private Peripheral Interrupt inputs as GPIO inputs.
The layout of the GPIO array is thus:
[0..N-1] SPIs
[N..N+31] PPIs for CPU 0
[N+32..N+63] PPIs for CPU 1
...
Treating PPIs as being another kind of input line is in line with the
GIC architecture specification, where they are clearly described that
way. The 11MPCore TRM is a bit more ambiguous, but there is no practical
difference between "set PPI X as pending" and "0->1 transition on a
PPI input line configured as edge triggered", and PPIs are always
edge triggered, so this change won't affect behaviour.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index df1a34b..fabbcc5 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -192,20 +192,40 @@ gic_set_pending_private(gic_state *s, int cpu, int irq)
/* Process a change in an external IRQ input. */
static void gic_set_irq(void *opaque, int irq, int level)
{
+ /* Meaning of the 'irq' parameter:
+ * [0..N-1] : external interrupts
+ * [N..N+31] : PPI (internal) interrupts for CPU 0
+ * [N+32..N+63] : PPI (internal interrupts for CPU 1
+ * ...
+ */
gic_state *s = (gic_state *)opaque;
- /* The first external input line is internal interrupt 32. */
- irq += GIC_INTERNAL;
- if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))
+ int cm, target;
+ if (irq < (s->num_irq - GIC_INTERNAL)) {
+ /* The first external input line is internal interrupt 32. */
+ cm = ALL_CPU_MASK;
+ irq += GIC_INTERNAL;
+ target = GIC_TARGET(irq);
+ } else {
+ int cpu;
+ irq -= (s->num_irq - GIC_INTERNAL);
+ cpu = irq / GIC_INTERNAL;
+ irq %= GIC_INTERNAL;
+ cm = 1 << cpu;
+ target = cm;
+ }
+
+ if (level == GIC_TEST_LEVEL(irq, cm)) {
return;
+ }
if (level) {
- GIC_SET_LEVEL(irq, ALL_CPU_MASK);
- if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, ALL_CPU_MASK)) {
- DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
- GIC_SET_PENDING(irq, GIC_TARGET(irq));
+ GIC_SET_LEVEL(irq, cm);
+ if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
+ DPRINTF("Set %d pending mask %x\n", irq, target);
+ GIC_SET_PENDING(irq, target);
}
} else {
- GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);
+ GIC_CLEAR_LEVEL(irq, cm);
}
gic_update(s);
}
@@ -849,7 +869,18 @@ static void gic_init(gic_state *s, int num_irq)
num_irq);
}
- qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - GIC_INTERNAL);
+ i = s->num_irq - GIC_INTERNAL;
+#ifndef NVIC
+ /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+ * GPIO array layout is thus:
+ * [0..N-1] SPIs
+ * [N..N+31] PPIs for CPU 0
+ * [N+32..N+63] PPIs for CPU 1
+ * ...
+ */
+ i += (GIC_INTERNAL * num_cpu);
+#endif
+ qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
for (i = 0; i < NUM_CPU(s); i++) {
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
commit 926c4aff6ecf2b26b3508773196314a774bf5c4c
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:07 2012 +0000
hw/arm_gic: Move gic_get_current_cpu into arm_gic.c
Move the gic_get_current_cpu() function into arm_gic.c.
There are only two implementations: (1) "get the index
of the currently executing CPU", used by all multicore
GICs, and (2) "always 0", used by all GICs instantiated
with a single CPU interface (the Realview board GIC and
the v7M NVIC). So we can move this into the main GIC
source file.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Evgeny Voevodin <e.voevodin at samsung.com>
diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
index 67206ec..2e2ed42 100644
--- a/hw/a15mpcore.c
+++ b/hw/a15mpcore.c
@@ -20,14 +20,6 @@
#include "sysbus.h"
-/* Configuration for arm_gic.c:
- * how to ID current CPU
- */
-static inline int gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
#include "arm_gic.c"
/* A15MP private memory region. */
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 5bbe3c7..1d83c37 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -10,15 +10,6 @@
#include "sysbus.h"
-/* Configuration for arm_gic.c:
- * how to ID current CPU
- */
-static inline int
-gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
#include "arm_gic.c"
/* A9MP private memory region. */
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index 99c1826..c4829d8 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,12 +10,6 @@
#include "sysbus.h"
#include "qemu-timer.h"
-static inline int
-gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
#include "arm_gic.c"
/* MPCore private memory region. */
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index f64a001..df1a34b 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -126,6 +126,16 @@ typedef struct gic_state
uint32_t num_irq;
} gic_state;
+static inline int gic_get_current_cpu(gic_state *s)
+{
+#if NCPU > 1
+ if (s->num_cpu > 1) {
+ return cpu_single_env->cpu_index;
+ }
+#endif
+ return 0;
+}
+
/* TODO: Many places that call this routine could be optimized. */
/* Update interrupt status after enabled or pending bits have been changed. */
static void gic_update(gic_state *s)
@@ -285,7 +295,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
int cm;
int mask;
- cpu = gic_get_current_cpu();
+ cpu = gic_get_current_cpu(s);
cm = 1 << cpu;
if (offset < 0x100) {
#ifndef NVIC
@@ -420,7 +430,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
int i;
int cpu;
- cpu = gic_get_current_cpu();
+ cpu = gic_get_current_cpu(s);
if (offset < 0x100) {
#ifdef NVIC
goto bad_reg;
@@ -582,7 +592,7 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
int irq;
int mask;
- cpu = gic_get_current_cpu();
+ cpu = gic_get_current_cpu(s);
irq = value & 0x3ff;
switch ((value >> 24) & 3) {
case 0:
@@ -665,14 +675,14 @@ static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
gic_state *s = (gic_state *)opaque;
- return gic_cpu_read(s, gic_get_current_cpu(), addr);
+ return gic_cpu_read(s, gic_get_current_cpu(s), addr);
}
static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned size)
{
gic_state *s = (gic_state *)opaque;
- gic_cpu_write(s, gic_get_current_cpu(), addr, value);
+ gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
}
/* Wrappers to read/write the GIC CPU interface for a specific CPU.
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index bdab709..99ed85b 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -17,13 +17,6 @@
#define NVIC 1
-/* Only a single "CPU" interface is present. */
-static inline int
-gic_get_current_cpu(void)
-{
- return 0;
-}
-
static uint32_t nvic_readl(void *opaque, uint32_t offset);
static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
index 426f540..ff7ab84 100644
--- a/hw/exynos4210_gic.c
+++ b/hw/exynos4210_gic.c
@@ -262,12 +262,6 @@ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
/********* GIC part *********/
-static inline int
-gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
#include "arm_gic.c"
typedef struct {
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index d114242..aa780fe 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,13 +9,6 @@
#include "sysbus.h"
-/* Only a single "CPU" interface is present. */
-static inline int
-gic_get_current_cpu(void)
-{
- return 0;
-}
-
#include "arm_gic.c"
typedef struct {
commit 386e29554e8f1a7e910682789418aed2094b4ef6
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 13 11:39:07 2012 +0000
hw/arm_gic: Move NCPU definition to arm_gic.c
Move the NCPU definition to arm_gic.c: the maximum number
of CPU interfaces is defined by the GIC architecture specification
to be 8, so we don't need to have this #define in each of the
sources files which currently includes arm_gic.c.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Evgeny Voevodin <e.voevodin at samsung.com>
diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
index 71142e5..67206ec 100644
--- a/hw/a15mpcore.c
+++ b/hw/a15mpcore.c
@@ -21,10 +21,8 @@
#include "sysbus.h"
/* Configuration for arm_gic.c:
- * max number of CPUs, how to ID current CPU
+ * how to ID current CPU
*/
-#define NCPU 4
-
static inline int gic_get_current_cpu(void)
{
return cpu_single_env->cpu_index;
@@ -45,10 +43,6 @@ static int a15mp_priv_init(SysBusDevice *dev)
{
A15MPPrivState *s = FROM_SYSBUSGIC(A15MPPrivState, dev);
- if (s->num_cpu > NCPU) {
- hw_error("a15mp_priv_init: num-cpu may not be more than %d\n", NCPU);
- }
-
gic_init(&s->gic, s->num_cpu, s->num_irq);
/* Memory map (addresses are offsets from PERIPHBASE):
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 03b128c..5bbe3c7 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -11,10 +11,8 @@
#include "sysbus.h"
/* Configuration for arm_gic.c:
- * max number of CPUs, how to ID current CPU
+ * how to ID current CPU
*/
-#define NCPU 4
-
static inline int
gic_get_current_cpu(void)
{
@@ -149,10 +147,6 @@ static int a9mp_priv_init(SysBusDevice *dev)
SysBusDevice *busdev;
int i;
- if (s->num_cpu > NCPU) {
- hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
- }
-
gic_init(&s->gic, s->num_cpu, s->num_irq);
s->mptimer = qdev_create(NULL, "arm_mptimer");
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index ba6a89d..99c1826 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,8 +10,6 @@
#include "sysbus.h"
#include "qemu-timer.h"
-#define NCPU 4
-
static inline int
gic_get_current_cpu(void)
{
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 6b34c06..f64a001 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -15,6 +15,13 @@
#define GIC_MAXIRQ 1020
/* First 32 are private to each CPU (SGIs and PPIs). */
#define GIC_INTERNAL 32
+/* Maximum number of possible CPU interfaces, determined by GIC architecture */
+#ifdef NVIC
+#define NCPU 1
+#else
+#define NCPU 8
+#endif
+
//#define DEBUG_GIC
#ifdef DEBUG_GIC
@@ -50,7 +57,7 @@ typedef struct gic_irq_state
unsigned trigger:1; /* nonzero = edge triggered. */
} gic_irq_state;
-#define ALL_CPU_MASK ((1 << NCPU) - 1)
+#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
#if NCPU > 1
#define NUM_CPU(s) ((s)->num_cpu)
#else
@@ -813,6 +820,10 @@ static void gic_init(gic_state *s, int num_irq)
#if NCPU > 1
s->num_cpu = num_cpu;
+ if (s->num_cpu > NCPU) {
+ hw_error("requested %u CPUs exceeds GIC maximum %d\n",
+ num_cpu, NCPU);
+ }
#endif
s->num_irq = num_irq + GIC_BASE_IRQ;
if (s->num_irq > GIC_MAXIRQ) {
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 3210129..bdab709 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -15,7 +15,6 @@
#include "arm-misc.h"
#include "exec-memory.h"
-#define NCPU 1
#define NVIC 1
/* Only a single "CPU" interface is present. */
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
index 3ba9063..426f540 100644
--- a/hw/exynos4210_gic.c
+++ b/hw/exynos4210_gic.c
@@ -174,7 +174,6 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
};
#define EXYNOS4210_GIC_NIRQ 160
-#define NCPU EXYNOS4210_NCPUS
#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000
#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000
@@ -275,8 +274,8 @@ typedef struct {
gic_state gic;
MemoryRegion cpu_container;
MemoryRegion dist_container;
- MemoryRegion cpu_alias[NCPU];
- MemoryRegion dist_alias[NCPU];
+ MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
+ MemoryRegion dist_alias[EXYNOS4210_NCPUS];
uint32_t num_cpu;
} Exynos4210GicState;
@@ -359,7 +358,7 @@ type_init(exynos4210_gic_register_types)
typedef struct {
SysBusDevice busdev;
- qemu_irq pic_irq[NCPU]; /* output IRQs to PICs */
+ qemu_irq pic_irq[EXYNOS4210_NCPUS]; /* output IRQs to PICs */
uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */
} Exynos4210IRQGateState;
@@ -424,7 +423,7 @@ static int exynos4210_irq_gate_init(SysBusDevice *dev)
EXYNOS4210_IRQ_GATE_NINPUTS);
/* Connect SysBusDev irqs to device specific irqs */
- for (i = 0; i < NCPU; i++) {
+ for (i = 0; i < EXYNOS4210_NCPUS; i++) {
sysbus_init_irq(dev, &s->pic_irq[i]);
}
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 071ef13..d114242 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,8 +9,6 @@
#include "sysbus.h"
-#define NCPU 1
-
/* Only a single "CPU" interface is present. */
static inline int
gic_get_current_cpu(void)
@@ -40,7 +38,7 @@ static int realview_gic_init(SysBusDevice *dev)
* number of interrupt lines, so we don't need to expose this as
* a qdev property.
*/
- gic_init(&s->gic, 96);
+ gic_init(&s->gic, 1, 96);
realview_gic_map_setup(s);
sysbus_init_mmio(dev, &s->container);
return 0;
commit 5181b50fc89d321cf79ed2f2fff5bec0b55e3011
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date: Fri Apr 13 11:39:06 2012 +0000
hw/exynos4210_combiner.c: Drop excessive read/write access check.
Access to reserved area at offset higher than 0x3c is allowed in
External Combiner. Samsung Galaxy Kernel implements this. So, drop
excessive checks in read/write functions.
Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c
index 6110c19..80af22c 100644
--- a/hw/exynos4210_combiner.c
+++ b/hw/exynos4210_combiner.c
@@ -184,11 +184,6 @@ exynos4210_combiner_read(void *opaque, target_phys_addr_t offset, unsigned size)
uint32_t reg_n; /* Register number inside the quad */
uint32_t val;
- if (s->external && (offset > 0x3c && offset != 0x100)) {
- hw_error("exynos4210.combiner: unallowed read access at offset 0x"
- TARGET_FMT_plx "\n", offset);
- }
-
req_quad_base_n = offset >> 4;
grp_quad_base_n = req_quad_base_n << 2;
reg_n = (offset - (req_quad_base_n << 4)) >> 2;
@@ -281,11 +276,6 @@ static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset,
uint32_t grp_quad_base_n; /* Base of group quad */
uint32_t reg_n; /* Register number inside the quad */
- if (s->external && (offset > 0x3c && offset != 0x100)) {
- hw_error("exynos4210.combiner: unallowed write access at offset 0x"
- TARGET_FMT_plx "\n", offset);
- }
-
req_quad_base_n = offset >> 4;
grp_quad_base_n = req_quad_base_n << 2;
reg_n = (offset - (req_quad_base_n << 4)) >> 2;
commit 3f088e36de5a72a69e530d4bbf1fabaa507da0db
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date: Fri Apr 13 11:39:06 2012 +0000
ARM: Exynos4210: Drop gic_cpu_write() after initialization.
Remove gic_cpu_write() call after initialization that was emulating
functionality of earliest SOC bootloader which enables external
GIC CPU1 interface. Instead introduce Exynos4210-specific secondary
CPU bootloader, which enables both Internal and External GIC CPU1
interfaces.
Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index f904370..afc4bdc 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -25,6 +25,7 @@
#include "sysemu.h"
#include "sysbus.h"
#include "arm-misc.h"
+#include "loader.h"
#include "exynos4210.h"
#define EXYNOS4210_CHIPID_ADDR 0x10000000
@@ -64,6 +65,35 @@
static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
0x09, 0x00, 0x00, 0x00 };
+void exynos4210_write_secondary(CPUARMState *env,
+ const struct arm_boot_info *info)
+{
+ int n;
+ uint32_t smpboot[] = {
+ 0xe59f3024, /* ldr r3, External gic_cpu_if */
+ 0xe59f2024, /* ldr r2, Internal gic_cpu_if */
+ 0xe59f0024, /* ldr r0, startaddr */
+ 0xe3a01001, /* mov r1, #1 */
+ 0xe5821000, /* str r1, [r2] */
+ 0xe5831000, /* str r1, [r3] */
+ 0xe320f003, /* wfi */
+ 0xe5901000, /* ldr r1, [r0] */
+ 0xe1110001, /* tst r1, r1 */
+ 0x0afffffb, /* beq <wfi> */
+ 0xe12fff11, /* bx r1 */
+ EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
+ 0, /* gic_cpu_if: base address of Internal GIC CPU interface */
+ 0 /* bootreg: Boot register address is held here */
+ };
+ smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
+ smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
+ for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+ smpboot[n] = tswap32(smpboot[n]);
+ }
+ rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+ info->smp_loader_start);
+}
+
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
unsigned long ram_size)
{
diff --git a/hw/exynos4210.h b/hw/exynos4210.h
index c112e03..f7c7027 100644
--- a/hw/exynos4210.h
+++ b/hw/exynos4210.h
@@ -97,6 +97,9 @@ typedef struct Exynos4210State {
MemoryRegion bootreg_mem;
} Exynos4210State;
+void exynos4210_write_secondary(CPUARMState *env,
+ const struct arm_boot_info *info);
+
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
unsigned long ram_size);
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
index ec13140..3ba9063 100644
--- a/hw/exynos4210_gic.c
+++ b/hw/exynos4210_gic.c
@@ -321,8 +321,6 @@ static int exynos4210_gic_init(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->cpu_container);
sysbus_init_mmio(dev, &s->dist_container);
- gic_cpu_write(&s->gic, 1, 0, 1);
-
return 0;
}
diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c
index 553a02b..ea32c51 100644
--- a/hw/exynos4_boards.c
+++ b/hw/exynos4_boards.c
@@ -70,6 +70,7 @@ static struct arm_boot_info exynos4_board_binfo = {
.loader_start = EXYNOS4210_BASE_BOOT_ADDR,
.smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
.nb_cpus = EXYNOS4210_NCPUS,
+ .write_secondary_boot = exynos4210_write_secondary,
};
static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS];
commit b85f62d7811c80646065f8f96c2248ea86cfd911
Author: Daniel P. Berrange <berrange at redhat.com>
Date: Fri Apr 13 11:39:06 2012 +0000
Fix bit test in Exynos4210 UART emulation to use & instead of &&
* hw/exynos4210_uart.c: s/&&/&/
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c
index 73a9c18..ccc4780 100644
--- a/hw/exynos4210_uart.c
+++ b/hw/exynos4210_uart.c
@@ -246,7 +246,7 @@ static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s)
uint32_t level = 0;
uint32_t reg;
- reg = (s->reg[I_(UFCON)] && UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
+ reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
switch (s->channel) {
@@ -275,9 +275,9 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s)
* The Tx interrupt is always requested if the number of data in the
* transmit FIFO is smaller than the trigger level.
*/
- if (s->reg[I_(UFCON)] && UFCON_FIFO_ENABLE) {
+ if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
- uint32_t count = (s->reg[I_(UFSTAT)] && UFSTAT_Tx_FIFO_COUNT) >>
+ uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
UFSTAT_Tx_FIFO_COUNT_SHIFT;
if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
commit 6ccea1e4d9a39d0bcf5be5a7b49270c2132b9dcb
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Thu Apr 12 19:09:52 2012 +0100
configure: Insist on a Python 2, not Python 3
Our Python scripts require Python 2 and will fail on Python 3, eg:
File "/home/petmay01/linaro/qemu-from-laptop/qemu/scripts/qapi-commands.py", line 378
except getopt.GetoptError, err:
^
SyntaxError: invalid syntax
Add a check to configure that Python is not a Python 3, so we can
fail with a comprehensible error rather than an obscure one.
Reported-by: Boris Matti <swiftos at lavabit.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/configure b/configure
index b392c6f..1d94acd 100755
--- a/configure
+++ b/configure
@@ -1242,6 +1242,14 @@ if ! has $python; then
exit 1
fi
+# Note that if the Python conditional here evaluates True we will exit
+# with status 1 which is a shell 'false' value.
+if ! "$python" -c 'import sys; sys.exit(sys.version_info[0] >= 3)'; then
+ echo "Python 2 required but '$python' is version 3 or better."
+ echo "Use --python=/path/to/python to specify a Python 2."
+ exit 1
+fi
+
if test -z "$target_list" ; then
target_list="$default_target_list"
else
commit d6ef40bf1881ddc82c8d64e72d412090efe1190e
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Thu Apr 12 12:43:41 2012 +0100
bsd-user: fix compile failure
bsd-user doesn't actually support reserving a memory area for the
guest address space, but we need to at least define the reserved_va
global so that cpu-all.h's RESERVED_VA macro will work correctly.
This fixes a compilation error introduced in commit 39879bb
which added a use of RESERVED_VA to h2g_valid().
Reported-by: Brad Smith <brad at comstyle.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 48cb715..0689e38 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -41,6 +41,7 @@ int singlestep;
unsigned long mmap_min_addr;
unsigned long guest_base;
int have_guest_base;
+unsigned long reserved_va;
#endif
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
commit f349c12c0434e29c79ecde89029320c4002f7253
Author: Eric B Munson <emunson at mgebm.net>
Date: Sat Apr 7 06:17:47 2012 +0530
kvmclock: guest stop notification
Often when a guest is stopped from the qemu console, it will report spurious
soft lockup warnings on resume. There are kernel patches being discussed that
will give the host the ability to tell the guest that it is being stopped and
should ignore the soft lockup warning that generates. This patch uses the qemu
Notifier system to tell the guest it is about to be stopped.
Signed-off-by: Eric B Munson <emunson at mgebm.net>
Signed-off-by: Raghavendra K T <raghavendra.kt at linux.vnet.ibm.com>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c
index 446bd62..824b978 100644
--- a/hw/kvm/clock.c
+++ b/hw/kvm/clock.c
@@ -65,9 +65,25 @@ static void kvmclock_vm_state_change(void *opaque, int running,
RunState state)
{
KVMClockState *s = opaque;
+ CPUArchState *penv = first_cpu;
+ int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL);
+ int ret;
if (running) {
s->clock_valid = false;
+
+ if (!cap_clock_ctrl) {
+ return;
+ }
+ for (penv = first_cpu; penv != NULL; penv = penv->next_cpu) {
+ ret = kvm_vcpu_ioctl(penv, KVM_KVMCLOCK_CTRL, 0);
+ if (ret) {
+ if (ret != -EINVAL) {
+ fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
+ }
+ return;
+ }
+ }
}
}
commit 9ab2195dcb2e7d202287b6db7cfaa4f9e01941f6
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date: Thu Apr 12 00:43:27 2012 -0300
kvm: update linux headers
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index b921c3f..1bea4d8 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -277,6 +277,7 @@ struct kvm_sync_regs {
#define KVM_CPU_E500V2 2
#define KVM_CPU_3S_32 3
#define KVM_CPU_3S_64 4
+#define KVM_CPU_E500MC 5
/* for KVM_CAP_SPAPR_TCE */
struct kvm_create_spapr_tce {
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index 9acbde4..9607667 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -44,10 +44,12 @@ struct kvm_guest_debug_arch {
#define KVM_SYNC_PREFIX (1UL << 0)
#define KVM_SYNC_GPRS (1UL << 1)
#define KVM_SYNC_ACRS (1UL << 2)
+#define KVM_SYNC_CRS (1UL << 3)
/* definition of registers in kvm_run */
struct kvm_sync_regs {
__u64 prefix; /* prefix register */
__u64 gprs[16]; /* general purpose registers */
__u32 acrs[16]; /* access registers */
+ __u64 crs[16]; /* control registers */
};
#endif
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index f6b5343..ee7bd9c 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -588,6 +588,8 @@ struct kvm_ppc_pvinfo {
#define KVM_CAP_TSC_DEADLINE_TIMER 72
#define KVM_CAP_S390_UCONTROL 73
#define KVM_CAP_SYNC_REGS 74
+#define KVM_CAP_PCI_2_3 75
+#define KVM_CAP_KVMCLOCK_CTRL 76
#ifdef KVM_CAP_IRQ_ROUTING
@@ -784,6 +786,9 @@ struct kvm_s390_ucas_mapping {
/* Available with KVM_CAP_TSC_CONTROL */
#define KVM_SET_TSC_KHZ _IO(KVMIO, 0xa2)
#define KVM_GET_TSC_KHZ _IO(KVMIO, 0xa3)
+/* Available with KVM_CAP_PCI_2_3 */
+#define KVM_ASSIGN_SET_INTX_MASK _IOW(KVMIO, 0xa4, \
+ struct kvm_assigned_pci_dev)
/*
* ioctls for vcpu fds
@@ -855,8 +860,12 @@ struct kvm_s390_ucas_mapping {
/* Available with KVM_CAP_ONE_REG */
#define KVM_GET_ONE_REG _IOW(KVMIO, 0xab, struct kvm_one_reg)
#define KVM_SET_ONE_REG _IOW(KVMIO, 0xac, struct kvm_one_reg)
+/* VM is being stopped by host */
+#define KVM_KVMCLOCK_CTRL _IO(KVMIO, 0xad)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
+#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
+#define KVM_DEV_ASSIGN_MASK_INTX (1 << 2)
struct kvm_assigned_pci_dev {
__u32 assigned_dev_id;
commit bc8c6788b60cbbe56700568bcb645e139ab29b7d
Author: Jason Baron <jbaron at redhat.com>
Date: Wed Mar 28 14:18:05 2012 -0400
kvm: set gsi_bits and max_gsi correctly
The current kvm_init_irq_routing() doesn't set up the used_gsi_bitmap
correctly, and as a consequence pins max_gsi to 32 when it really
should be 1024. I ran into this limitation while testing pci
passthrough, where I consistently got an -ENOSPC return from
kvm_get_irq_route_gsi() called from assigned_dev_update_msix_mmio().
Signed-off-by: Jason Baron <jbaron at redhat.com>
Acked-by: Alex Williamson <alex.williamson at redhat.com>
Acked-by: Jan Kiszka <jan.kiszka at siemens.com>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/kvm-all.c b/kvm-all.c
index 5ff954a..b8e9dc6 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -871,7 +871,7 @@ static void kvm_init_irq_routing(KVMState *s)
unsigned int gsi_bits, i;
/* Round up so we can search ints using ffs */
- gsi_bits = (gsi_count + 31) / 32;
+ gsi_bits = ALIGN(gsi_count, 32);
s->used_gsi_bitmap = g_malloc0(gsi_bits / 8);
s->max_gsi = gsi_bits;
commit c73b00973b13a4a1e823ce935bcfe264c758b40b
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Thu Mar 22 00:00:48 2012 +0100
kvm: Drop unused kvm_pit_in_kernel
This is now implied by kvm_irqchip_in_kernel.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/kvm-all.c b/kvm-all.c
index f1cb69f..5ff954a 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -75,7 +75,6 @@ struct KVMState
#ifdef KVM_CAP_SET_GUEST_DEBUG
struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
#endif
- int pit_in_kernel;
int pit_state2;
int xsave, xcrs;
int many_ioeventfds;
@@ -198,11 +197,6 @@ static void kvm_reset_vcpu(void *opaque)
kvm_arch_reset_vcpu(env);
}
-int kvm_pit_in_kernel(void)
-{
- return kvm_state->pit_in_kernel;
-}
-
int kvm_init_vcpu(CPUArchState *env)
{
KVMState *s = kvm_state;
diff --git a/kvm-stub.c b/kvm-stub.c
index 0d426db..47c573d 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -16,12 +16,6 @@
#include "gdbstub.h"
#include "kvm.h"
-int kvm_pit_in_kernel(void)
-{
- return 0;
-}
-
-
int kvm_init_vcpu(CPUArchState *env)
{
return -ENOSYS;
diff --git a/kvm.h b/kvm.h
index 9bdbdb0..4ccae8c 100644
--- a/kvm.h
+++ b/kvm.h
@@ -83,8 +83,6 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap);
int kvm_set_signal_mask(CPUArchState *env, const sigset_t *sigset);
#endif
-int kvm_pit_in_kernel(void);
-
int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr);
int kvm_on_sigbus(int code, void *addr);
commit 4b8f1c88e9de2ded754b12a967a93d395bed1245
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Tue Mar 20 14:31:38 2012 +0200
kvm: allow arbitrarily sized mmio ioeventfd
We use a 2 byte ioeventfd for virtio memory,
add support for this.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
Reviewed-by: Amos Kong <akong at redhat.com>
Signed-off-by: Avi Kivity <avi at redhat.com>
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index b80aa8f..df4f50a 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -354,8 +354,8 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
guest_curr_max = s->peers[posn].nb_eventfds;
for (i = 0; i < guest_curr_max; i++) {
- kvm_set_ioeventfd_mmio_long(s->peers[posn].eventfds[i],
- s->mmio_addr + DOORBELL, (posn << 16) | i, 0);
+ kvm_set_ioeventfd_mmio(s->peers[posn].eventfds[i],
+ s->mmio_addr + DOORBELL, (posn << 16) | i, 0, 4);
close(s->peers[posn].eventfds[i]);
}
@@ -500,8 +500,8 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
}
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
- if (kvm_set_ioeventfd_mmio_long(incoming_fd, s->mmio_addr + DOORBELL,
- (incoming_posn << 16) | guest_max_eventfd, 1) < 0) {
+ if (kvm_set_ioeventfd_mmio(incoming_fd, s->mmio_addr + DOORBELL,
+ (incoming_posn << 16) | guest_max_eventfd, 1, 4) < 0) {
fprintf(stderr, "ivshmem: ioeventfd not available\n");
}
}
diff --git a/kvm-all.c b/kvm-all.c
index ba2cee1..f1cb69f 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -747,10 +747,10 @@ static void kvm_mem_ioeventfd_add(MemoryRegionSection *section,
{
int r;
- assert(match_data && section->size == 4);
+ assert(match_data && section->size <= 8);
- r = kvm_set_ioeventfd_mmio_long(fd, section->offset_within_address_space,
- data, true);
+ r = kvm_set_ioeventfd_mmio(fd, section->offset_within_address_space,
+ data, true, section->size);
if (r < 0) {
abort();
}
@@ -761,8 +761,8 @@ static void kvm_mem_ioeventfd_del(MemoryRegionSection *section,
{
int r;
- r = kvm_set_ioeventfd_mmio_long(fd, section->offset_within_address_space,
- data, false);
+ r = kvm_set_ioeventfd_mmio(fd, section->offset_within_address_space,
+ data, false, section->size);
if (r < 0) {
abort();
}
@@ -1642,14 +1642,15 @@ int kvm_set_signal_mask(CPUArchState *env, const sigset_t *sigset)
return r;
}
-int kvm_set_ioeventfd_mmio_long(int fd, uint32_t addr, uint32_t val, bool assign)
+int kvm_set_ioeventfd_mmio(int fd, uint32_t addr, uint32_t val, bool assign,
+ uint32_t size)
{
int ret;
struct kvm_ioeventfd iofd;
iofd.datamatch = val;
iofd.addr = addr;
- iofd.len = 4;
+ iofd.len = size;
iofd.flags = KVM_IOEVENTFD_FLAG_DATAMATCH;
iofd.fd = fd;
diff --git a/kvm-stub.c b/kvm-stub.c
index 69a1228..0d426db 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -120,7 +120,7 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
return -ENOSYS;
}
-int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
+int kvm_set_ioeventfd_mmio(int fd, uint32_t adr, uint32_t val, bool assign, uint32_t len)
{
return -ENOSYS;
}
diff --git a/kvm.h b/kvm.h
index 330f17b..9bdbdb0 100644
--- a/kvm.h
+++ b/kvm.h
@@ -210,7 +210,8 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
#endif
#endif
-int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign);
+int kvm_set_ioeventfd_mmio(int fd, uint32_t adr, uint32_t val, bool assign,
+ uint32_t size);
int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign);
#endif
commit 56b9ead234439317629054fa370c547c652ab09a
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Wed Mar 21 13:36:22 2012 +0100
kvm: Drop redundant kvm_enabled from cpu_thread_is_idle
This is now implied by kvm_irqchip_in_kernel.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
Signed-off-by: Avi Kivity <avi at redhat.com>
diff --git a/cpus.c b/cpus.c
index eb22bd5..b182b3d 100644
--- a/cpus.c
+++ b/cpus.c
@@ -441,8 +441,7 @@ static bool cpu_thread_is_idle(CPUArchState *env)
if (env->stopped || !runstate_is_running()) {
return true;
}
- if (!env->halted || qemu_cpu_has_work(env) ||
- (kvm_enabled() && kvm_irqchip_in_kernel())) {
+ if (!env->halted || qemu_cpu_has_work(env) || kvm_irqchip_in_kernel()) {
return false;
}
return true;
commit b3c09bde4842f1b157bc4431135aad4f2031e312
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Fri Mar 9 14:13:40 2012 +0000
kvm: add flightrecorder script
The kvm kernel module includes a number of trace events which can be
useful when debugging system behavior. Even on production systems these
trace events can be used to observe guest behavior and identify the
source of problems.
The kvm_flightrecorder script is a command-line wrapper for the
/sys/kernel/debug/tracing interface. Kernel symbols do not need to be
installed.
This script captures a fixed-size buffer of KVM trace events. Recent
events overwrite the oldest events when the buffer size is exceeded and
it is possible to leave KVM tracing enabled for any period of time with
just a fixed-size buffer. If the buffer is large enough this script is
a useful tool for collecting detailed information after an issue occurs
with a guest. Hence the name "flight recorder".
The script can also be used in 'tail' mode to simply view KVM trace
events as they occur. This is handy for development and to ensure that
the guest is indeed running.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/scripts/kvm/kvm_flightrecorder b/scripts/kvm/kvm_flightrecorder
new file mode 100755
index 0000000..7fb1c2d
--- /dev/null
+++ b/scripts/kvm/kvm_flightrecorder
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+#
+# KVM Flight Recorder - ring buffer tracing script
+#
+# Copyright (C) 2012 IBM Corp
+#
+# Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
+#
+# This script provides a command-line interface to kvm ftrace and is designed
+# to be used as a flight recorder that is always running. To start in-memory
+# recording:
+#
+# sudo kvm_flightrecorder start 8192 # 8 MB per-cpu ring buffers
+#
+# The per-cpu ring buffer size can be given in KB as an optional argument to
+# the 'start' subcommand.
+#
+# To stop the flight recorder:
+#
+# sudo kvm_flightrecorder stop
+#
+# To dump the contents of the flight recorder (this can be done when the
+# recorder is stopped or while it is running):
+#
+# sudo kvm_flightrecorder dump >/path/to/dump.txt
+#
+# To observe the trace while it is running, use the 'tail' subcommand:
+#
+# sudo kvm_flightrecorder tail
+#
+# Note that the flight recorder may impact overall system performance by
+# consuming CPU cycles. No disk I/O is performed since the ring buffer holds a
+# fixed-size in-memory trace.
+
+import sys
+import os
+
+tracing_dir = '/sys/kernel/debug/tracing'
+
+def trace_path(*args):
+ return os.path.join(tracing_dir, *args)
+
+def write_file(path, data):
+ open(path, 'wb').write(data)
+
+def enable_event(subsystem, event, enable):
+ write_file(trace_path('events', subsystem, event, 'enable'), '1' if enable else '0')
+
+def enable_subsystem(subsystem, enable):
+ write_file(trace_path('events', subsystem, 'enable'), '1' if enable else '0')
+
+def start_tracing():
+ enable_subsystem('kvm', True)
+ write_file(trace_path('tracing_on'), '1')
+
+def stop_tracing():
+ write_file(trace_path('tracing_on'), '0')
+ enable_subsystem('kvm', False)
+ write_file(trace_path('events', 'enable'), '0')
+ write_file(trace_path('current_tracer'), 'nop')
+
+def dump_trace():
+ tracefile = open(trace_path('trace'), 'r')
+ try:
+ lines = True
+ while lines:
+ lines = tracefile.readlines(64 * 1024)
+ sys.stdout.writelines(lines)
+ except KeyboardInterrupt:
+ pass
+
+def tail_trace():
+ try:
+ for line in open(trace_path('trace_pipe'), 'r'):
+ sys.stdout.write(line)
+ except KeyboardInterrupt:
+ pass
+
+def usage():
+ print 'Usage: %s start [buffer_size_kb] | stop | dump | tail' % sys.argv[0]
+ print 'Control the KVM flight recorder tracing.'
+ sys.exit(0)
+
+def main():
+ if len(sys.argv) < 2:
+ usage()
+
+ cmd = sys.argv[1]
+ if cmd == '--version':
+ print 'kvm_flightrecorder version 1.0'
+ sys.exit(0)
+
+ if not os.path.isdir(tracing_dir):
+ print 'Unable to tracing debugfs directory, try:'
+ print 'mount -t debugfs none /sys/kernel/debug'
+ sys.exit(1)
+ if not os.access(tracing_dir, os.W_OK):
+ print 'Unable to write to tracing debugfs directory, please run as root'
+ sys.exit(1)
+
+ if cmd == 'start':
+ stop_tracing() # clean up first
+
+ if len(sys.argv) == 3:
+ try:
+ buffer_size_kb = int(sys.argv[2])
+ except ValueError:
+ print 'Invalid per-cpu trace buffer size in KB'
+ sys.exit(1)
+ write_file(trace_path('buffer_size_kb'), str(buffer_size_kb))
+ print 'Per-CPU ring buffer size set to %d KB' % buffer_size_kb
+
+ start_tracing()
+ print 'KVM flight recorder enabled'
+ elif cmd == 'stop':
+ stop_tracing()
+ print 'KVM flight recorder disabled'
+ elif cmd == 'dump':
+ dump_trace()
+ elif cmd == 'tail':
+ tail_trace()
+ else:
+ usage()
+
+if __name__ == '__main__':
+ sys.exit(main())
commit fd65f595fe14dafeee1cd34df0dbe288ed6a5f06
Author: Wanpeng Li <liwp at linux.vnet.ibm.com>
Date: Wed Apr 11 09:02:21 2012 +0800
ps2: avoid repeated header file includes
Signed-off-by: Wanpeng Li <liwp at linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hw/ps2.h b/hw/ps2.h
index 32a4231..7c45ce7 100644
--- a/hw/ps2.h
+++ b/hw/ps2.h
@@ -1,3 +1,30 @@
+/*
+ * QEMU PS/2 keyboard/mouse emulation
+ *
+ * Copyright (C) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_PS2_H
+#define HW_PS2_H
+
/* ps2.c */
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
@@ -7,3 +34,5 @@ uint32_t ps2_read_data(void *);
void ps2_queue(void *, int b);
void ps2_keyboard_set_translation(void *opaque, int mode);
void ps2_mouse_fake_event(void *opaque);
+
+#endif /* !HW_PS2_H */
commit 952ef67cc06a636fe11344e3a11137d146222bc4
Author: Stefan Weil <sw at weilnetz.de>
Date: Tue Mar 27 19:15:27 2012 +0200
make: Always set LC_ALL=C for makeinfo
Otherwise the generated file qemu-doc.html will contain "Anhang"
instead of "Appendix" with a German locale (de_DE.UTF-8).
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/Makefile b/Makefile
index a78f53d..e0fe680 100644
--- a/Makefile
+++ b/Makefile
@@ -328,7 +328,7 @@ TEXIFLAG=$(if $(V),,--quiet)
$(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<," GEN $@")
%.html: %.texi
- $(call quiet-command,$(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \
+ $(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \
" GEN $@")
%.info: %.texi
commit e172fe1177ffa14f6d13cc539dd80d2a2705aa73
Author: Stefan Weil <sw at weilnetz.de>
Date: Fri Apr 6 21:33:20 2012 +0200
configure: Fix wrong preprocessor statement
#abort is not a preprocessor statement. It aborts, but the preprocessor
statement #error is more common to abort a compilation.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/configure b/configure
index 5aaafa1..b392c6f 100755
--- a/configure
+++ b/configure
@@ -2624,7 +2624,7 @@ int main(void) {
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
return fdatasync(0);
#else
-#abort Not supported
+#error Not supported
#endif
}
EOF
commit 8fb03151651cc61f68f8032374c9c08dc129b9d9
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Wed Apr 4 17:03:15 2012 +0100
configure: Remove useless uses of ARCH_CFLAGS
Remove some useless uses of ARCH_CFLAGS -- this variable was never set
so will always be empty. The uses were accidental: in commit 0c439cbf8
Juan Quintela removed ARCH_CFLAGS in favour of CFLAGS (which in turn
became QEMU_CFLAGS). However in commit be17dc90 a use of it was
reintroduced (apparently accidentally) by Michael S. Tsirkin, and then
I subsequently cut-n-pasted that into a number of other configure
feature tests.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Reviewed-by: Juan Quintela <quintela at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/configure b/configure
index e05f34b..5aaafa1 100755
--- a/configure
+++ b/configure
@@ -2369,7 +2369,7 @@ int main(void)
return 0;
}
EOF
-if compile_prog "$ARCH_CFLAGS" "" ; then
+if compile_prog "" "" ; then
fallocate=yes
fi
@@ -2384,7 +2384,7 @@ int main(void)
return 0;
}
EOF
-if compile_prog "$ARCH_CFLAGS" "" ; then
+if compile_prog "" "" ; then
sync_file_range=yes
fi
@@ -2401,7 +2401,7 @@ int main(void)
return 0;
}
EOF
-if compile_prog "$ARCH_CFLAGS" "" ; then
+if compile_prog "" "" ; then
fiemap=yes
fi
@@ -2431,7 +2431,7 @@ int main(void)
return 0;
}
EOF
-if compile_prog "$ARCH_CFLAGS" "" ; then
+if compile_prog "" "" ; then
epoll=yes
fi
@@ -2454,7 +2454,7 @@ int main(void)
return epoll_create1 == epoll_create1;
}
EOF
-if compile_prog "$ARCH_CFLAGS" "" ; then
+if compile_prog "" "" ; then
epoll_create1=yes
fi
@@ -2468,7 +2468,7 @@ int main(void)
return 0;
}
EOF
-if compile_prog "$ARCH_CFLAGS" "" ; then
+if compile_prog "" "" ; then
epoll_pwait=yes
fi
commit dadc1064c348545695b8a14d9dc72ccaa2983be7
Author: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
Date: Thu Apr 12 14:30:30 2012 +1000
target-microblaze: added PetaLogix copyright
Microblaze cpu development has been driven and funded by PetaLogix. Added (c)
PetaLogix line accordingly.
Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c
index 6e0e411..2412a58 100644
--- a/target-microblaze/helper.c
+++ b/target-microblaze/helper.c
@@ -2,6 +2,7 @@
* MicroBlaze helper routines.
*
* Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias at gmail.com>
+ * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/target-microblaze/mmu.c b/target-microblaze/mmu.c
index 43092e5..53ad263 100644
--- a/target-microblaze/mmu.c
+++ b/target-microblaze/mmu.c
@@ -2,6 +2,7 @@
* Microblaze MMU emulation for qemu.
*
* Copyright (c) 2009 Edgar E. Iglesias
+ * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index 76cc0e0..a83da8d 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -2,6 +2,7 @@
* Microblaze helper routines.
*
* Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias at gmail.com>.
+ * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 64cbfb8..b602820 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -2,6 +2,7 @@
* Xilinx MicroBlaze emulation for qemu: main translation routines.
*
* Copyright (c) 2009 Edgar E. Iglesias.
+ * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
commit 3eab1690851fa68698612d9dd9d5231759f549c2
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 01:37:45 2012 +0200
target-lm32: QOM'ify CPU reset
Move code from cpu_state_reset() into QOM lm32_cpu_reset().
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Michael Walle <michael at walle.cc>
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index 70251d0..48a5fe3 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -29,9 +29,17 @@ static void lm32_cpu_reset(CPUState *s)
LM32CPUClass *lcc = LM32_CPU_GET_CLASS(cpu);
CPULM32State *env = &cpu->env;
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
lcc->parent_reset(s);
- cpu_state_reset(env);
+ tlb_flush(env, 1);
+
+ /* reset cpu state */
+ memset(env, 0, offsetof(CPULM32State, breakpoints));
}
static void lm32_cpu_initfn(Object *obj)
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 9de777f..d0bc193 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -236,14 +236,6 @@ void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value)
void cpu_state_reset(CPULM32State *env)
{
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- tlb_flush(env, 1);
-
- /* reset cpu state */
- memset(env, 0, offsetof(CPULM32State, breakpoints));
+ cpu_reset(ENV_GET_CPU(env));
}
commit 8d7d505adda444220c93ee5ad09df4176b366bd7
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 01:33:33 2012 +0200
target-lm32: QOM'ify CPU init
Move code from cpu_lm32_init() to an initfn; call cpu_reset()
instead of cpu_state_reset().
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Michael Walle <michael at walle.cc>
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index 4ce7e3b..70251d0 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -34,6 +34,18 @@ static void lm32_cpu_reset(CPUState *s)
cpu_state_reset(env);
}
+static void lm32_cpu_initfn(Object *obj)
+{
+ LM32CPU *cpu = LM32_CPU(obj);
+ CPULM32State *env = &cpu->env;
+
+ cpu_exec_init(env);
+
+ env->flags = 0;
+
+ cpu_reset(CPU(cpu));
+}
+
static void lm32_cpu_class_init(ObjectClass *oc, void *data)
{
LM32CPUClass *lcc = LM32_CPU_CLASS(oc);
@@ -47,6 +59,7 @@ static const TypeInfo lm32_cpu_type_info = {
.name = TYPE_LM32_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(LM32CPU),
+ .instance_init = lm32_cpu_initfn,
.abstract = false,
.class_size = sizeof(LM32CPUClass),
.class_init = lm32_cpu_class_init,
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 3cf86d7..9de777f 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -211,10 +211,7 @@ CPULM32State *cpu_lm32_init(const char *cpu_model)
env->num_bps = def->num_breakpoints;
env->num_wps = def->num_watchpoints;
env->cfg = cfg_by_def(def);
- env->flags = 0;
- cpu_exec_init(env);
- cpu_state_reset(env);
qemu_init_vcpu(env);
if (tcg_enabled() && !tcg_initialized) {
commit fc0ced2fbd8d40672fcdd2f655bbdcd3e278f3ab
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 01:22:08 2012 +0200
target-lm32: QOM'ify CPU
Embed CPULM32State as first member of QOM LM32CPU.
Let CPUClass::reset() call cpu_state_reset() for now.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Michael Walle <michael at walle.cc>
diff --git a/Makefile.target b/Makefile.target
index 1110796..e88b896 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -93,6 +93,7 @@ libobj-$(TARGET_SPARC64) += vis_helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-$(TARGET_ARM) += cpu.o
+libobj-$(TARGET_LM32) += cpu.o
libobj-$(TARGET_S390X) += cpu.o
ifeq ($(TARGET_BASE_ARCH), sparc)
libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h
new file mode 100644
index 0000000..4ae2edd
--- /dev/null
+++ b/target-lm32/cpu-qom.h
@@ -0,0 +1,71 @@
+/*
+ * QEMU LatticeMico32 CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_LM32_CPU_QOM_H
+#define QEMU_LM32_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_LM32_CPU "lm32-cpu"
+
+#define LM32_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(LM32CPUClass, (klass), TYPE_LM32_CPU)
+#define LM32_CPU(obj) \
+ OBJECT_CHECK(LM32CPU, (obj), TYPE_LM32_CPU)
+#define LM32_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(LM32CPUClass, (obj), TYPE_LM32_CPU)
+
+/**
+ * LM32CPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A LatticeMico32 CPU model.
+ */
+typedef struct LM32CPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} LM32CPUClass;
+
+/**
+ * LM32CPU:
+ * @env: #CPULM32State
+ *
+ * A LatticeMico32 CPU.
+ */
+typedef struct LM32CPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPULM32State env;
+} LM32CPU;
+
+static inline LM32CPU *lm32_env_get_cpu(CPULM32State *env)
+{
+ return LM32_CPU(container_of(env, LM32CPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(lm32_env_get_cpu(e))
+
+
+#endif
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
new file mode 100644
index 0000000..4ce7e3b
--- /dev/null
+++ b/target-lm32/cpu.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU LatticeMico32 CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+
+
+/* CPUClass::reset() */
+static void lm32_cpu_reset(CPUState *s)
+{
+ LM32CPU *cpu = LM32_CPU(s);
+ LM32CPUClass *lcc = LM32_CPU_GET_CLASS(cpu);
+ CPULM32State *env = &cpu->env;
+
+ lcc->parent_reset(s);
+
+ cpu_state_reset(env);
+}
+
+static void lm32_cpu_class_init(ObjectClass *oc, void *data)
+{
+ LM32CPUClass *lcc = LM32_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
+
+ lcc->parent_reset = cc->reset;
+ cc->reset = lm32_cpu_reset;
+}
+
+static const TypeInfo lm32_cpu_type_info = {
+ .name = TYPE_LM32_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(LM32CPU),
+ .abstract = false,
+ .class_size = sizeof(LM32CPUClass),
+ .class_init = lm32_cpu_class_init,
+};
+
+static void lm32_cpu_register_types(void)
+{
+ type_register_static(&lm32_cpu_type_info);
+}
+
+type_init(lm32_cpu_register_types)
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index a7d9546..422a55b 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -184,6 +184,7 @@ struct CPULM32State {
};
+#include "cpu-qom.h"
CPULM32State *cpu_lm32_init(const char *cpu_model);
void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf);
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 78076e4..3cf86d7 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -194,6 +194,7 @@ static uint32_t cfg_by_def(const LM32Def *def)
CPULM32State *cpu_lm32_init(const char *cpu_model)
{
+ LM32CPU *cpu;
CPULM32State *env;
const LM32Def *def;
static int tcg_initialized;
@@ -203,7 +204,8 @@ CPULM32State *cpu_lm32_init(const char *cpu_model)
return NULL;
}
- env = g_malloc0(sizeof(CPULM32State));
+ cpu = LM32_CPU(object_new(TYPE_LM32_CPU));
+ env = &cpu->env;
env->features = def->features;
env->num_bps = def->num_breakpoints;
commit 3e48dd4a2d48aabafe22ce3611d65544d0234a69
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Wed Apr 11 12:01:44 2012 +0100
rtl8139: do not assume TxStatus[] and TxAddr[] are adjacent
Commit afe0a595356192d5f79703cf6462fcc112df007c ("rtl8139: support byte
read to TxStatus registers") reused rtl8139_TxStatus_read() for reading
TxAddr registers. It relies on the fact that TxStatus[] and TxAddr[]
are adjacent.
This causes a gcc warning because the compiler can detect that array
access is out-of-bounds:
hw/rtl8139.c:2501:27: error: array subscript is above array bounds [-Werror=array-bounds]
This patch refactors the function so that we don't rely on out-of-bounds
accesses.
Cc: Jason Wang <jasonwang at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 4d553a8..4d0f5ba 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -2482,15 +2482,17 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32
rtl8139_transmit(s);
}
-static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint8_t addr, int size)
+static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[],
+ uint32_t base, uint8_t addr,
+ int size)
{
- uint32_t reg = (addr - TxStatus0) / 4;
+ uint32_t reg = (addr - base) / 4;
uint32_t offset = addr & 0x3;
uint32_t ret = 0;
if (addr & (size - 1)) {
- DPRINTF("not implemented read for TxStatus addr=0x%x size=0x%x\n", addr,
- size);
+ DPRINTF("not implemented read for TxStatus/TxAddr "
+ "addr=0x%x size=0x%x\n", addr, size);
return ret;
}
@@ -2498,12 +2500,12 @@ static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint8_t addr, int size)
case 1: /* fall through */
case 2: /* fall through */
case 4:
- ret = (s->TxStatus[reg] >> offset * 8) & ((1 << (size * 8)) - 1);
- DPRINTF("TxStatus[%d] read addr=0x%x size=0x%x val=0x%08x\n", reg, addr,
- size, ret);
+ ret = (regs[reg] >> offset * 8) & ((1 << (size * 8)) - 1);
+ DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n",
+ reg, addr, size, ret);
break;
default:
- DPRINTF("unsupported size 0x%x of TxStatus reading\n", size);
+ DPRINTF("unsupported size 0x%x of TxStatus/TxAddr reading\n", size);
break;
}
@@ -2977,7 +2979,8 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
ret = s->mult[addr - MAR0];
break;
case TxStatus0 ... TxStatus0+4*4-1:
- ret = rtl8139_TxStatus_read(s, addr, 1);
+ ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
+ addr, 1);
break;
case ChipCmd:
ret = rtl8139_ChipCmd_read(s);
@@ -3043,7 +3046,7 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
switch (addr)
{
case TxAddr0 ... TxAddr0+4*4-1:
- ret = rtl8139_TxStatus_read(s, addr, 2);
+ ret = rtl8139_TxStatus_TxAddr_read(s, s->TxAddr, TxAddr0, addr, 2);
break;
case IntrMask:
ret = rtl8139_IntrMask_read(s);
@@ -3135,7 +3138,8 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
break;
case TxStatus0 ... TxStatus0+4*4-1:
- ret = rtl8139_TxStatus_read(s, addr, 4);
+ ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
+ addr, 4);
break;
case TxAddr0 ... TxAddr0+4*4-1:
commit 2ba1d381c2f5f5868fe071b45977c2ed459d78f0
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Tue Apr 3 17:24:11 2012 +0300
virtio-pci: change virtio balloon PCI class code
Currently the virtio balloon device, when using the virtio-pci interface
advertises itself with PCI class code MEMORY_RAM. This is wrong; the
balloon is vaguely related to memory, but is nothing like a PCI memory
device in the meaning of the class code, and this code is not required
or suggested by the virtio PCI specification.
Worse, this patch causes problems on the pseries machine, because the
firmware, seeing this class code, advertises the device as memory in the
device tree, and then a guest kernel bug causes it to see this "memory"
before the real system memory, leading to a crash in early boot.
This patch fixes the problem by removing the bogus PCI class code on the
balloon device. The backwards compatibility PC machines get new compat
properties so that they don't change.
Cc: Rusty Russell <rusty at rustcorp.com.au>
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 0f61f00..5c08245 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -28,6 +28,7 @@
#include "pc.h"
#include "apic.h"
#include "pci.h"
+#include "pci_ids.h"
#include "net.h"
#include "boards.h"
#include "ide.h"
@@ -368,6 +369,10 @@ static QEMUMachine pc_machine_v1_1 = {
.driver = "isa-fdc",\
.property = "check_media_rate",\
.value = "off",\
+ }, {\
+ .driver = "virtio-balloon-pci",\
+ .property = "class",\
+ .value = stringify(PCI_CLASS_MEMORY_RAM),\
}
static QEMUMachine pc_machine_v1_0 = {
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index a0fb7c1..4a4413d 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -790,6 +790,11 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
VirtIODevice *vdev;
+ if (proxy->class_code != PCI_CLASS_OTHERS &&
+ proxy->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
+ proxy->class_code = PCI_CLASS_OTHERS;
+ }
+
vdev = virtio_balloon_init(&pci_dev->qdev);
if (!vdev) {
return -1;
@@ -906,6 +911,7 @@ static TypeInfo virtio_serial_info = {
static Property virtio_balloon_properties[] = {
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -919,7 +925,7 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data)
k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
k->revision = VIRTIO_PCI_ABI_VERSION;
- k->class_id = PCI_CLASS_MEMORY_RAM;
+ k->class_id = PCI_CLASS_OTHERS;
dc->reset = virtio_pci_reset;
dc->props = virtio_balloon_properties;
}
commit 4490c71191b59dce2dd88f5f9ab49f2c92ab410c
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Mon Dec 5 21:48:43 2011 +0200
ivshmem: add missing msix calls
ivshmem used msix but didn't call it on either reset or
config write paths. This used to partically work since
guests don't use all of msi-x configuration fields,
and reset is rarely used, but the patch 'msix: track function masked
in pci device state' broke that. Fix by adding appropriate calls.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
Reported-by: Cam Macdonell <cam at cs.ualberta.ca>
Tested-by: Cam Macdonell <cam at cs.ualberta.ca>
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index b80aa8f..c2bdd92 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -509,11 +509,29 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
return;
}
+/* Select the MSI-X vectors used by device.
+ * ivshmem maps events to vectors statically, so
+ * we just enable all vectors on init and after reset. */
+static void ivshmem_use_msix(IVShmemState * s)
+{
+ int i;
+
+ if (!msix_present(&s->dev)) {
+ return;
+ }
+
+ for (i = 0; i < s->vectors; i++) {
+ msix_vector_use(&s->dev, i);
+ }
+}
+
static void ivshmem_reset(DeviceState *d)
{
IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
s->intrstatus = 0;
+ msix_reset(&s->dev);
+ ivshmem_use_msix(s);
return;
}
@@ -544,12 +562,8 @@ static uint64_t ivshmem_get_size(IVShmemState * s) {
return value;
}
-static void ivshmem_setup_msi(IVShmemState * s) {
-
- int i;
-
- /* allocate the MSI-X vectors */
-
+static void ivshmem_setup_msi(IVShmemState * s)
+{
memory_region_init(&s->msix_bar, "ivshmem-msix", 4096);
if (!msix_init(&s->dev, s->vectors, &s->msix_bar, 1, 0)) {
pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
@@ -560,13 +574,10 @@ static void ivshmem_setup_msi(IVShmemState * s) {
exit(1);
}
- /* 'activate' the vectors */
- for (i = 0; i < s->vectors; i++) {
- msix_vector_use(&s->dev, i);
- }
-
/* allocate QEMU char devices for receiving interrupts */
s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
+
+ ivshmem_use_msix(s);
}
static void ivshmem_save(QEMUFile* f, void *opaque)
@@ -590,7 +601,7 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
IVSHMEM_DPRINTF("ivshmem_load\n");
IVShmemState *proxy = opaque;
- int ret, i;
+ int ret;
if (version_id > 0) {
return -EINVAL;
@@ -608,9 +619,7 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
msix_load(&proxy->dev, f);
- for (i = 0; i < proxy->vectors; i++) {
- msix_vector_use(&proxy->dev, i);
- }
+ ivshmem_use_msix(proxy);
} else {
proxy->intrstatus = qemu_get_be32(f);
proxy->intrmask = qemu_get_be32(f);
@@ -619,6 +628,13 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
return 0;
}
+static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
+ uint32_t val, int len)
+{
+ pci_default_write_config(pci_dev, address, val, len);
+ msix_write_config(pci_dev, address, val, len);
+}
+
static int pci_ivshmem_init(PCIDevice *dev)
{
IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
@@ -744,6 +760,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
}
+ s->dev.config_write = ivshmem_write_config;
+
return 0;
}
commit fbbaf9ae88286f18b2ab32fb4174ebdbdc1d5919
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Apr 1 11:39:43 2012 +0300
vhost: readd assert statement
It's clear from the surrounding code that
start < end so it's enough to assert end < log_size.
However, it's better to make this explicit in case
we refactor the code again.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/vhost.c b/hw/vhost.c
index 7e282dd..43664e7 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -35,6 +35,7 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
return;
}
assert(end / VHOST_LOG_CHUNK < dev->log_size);
+ assert(start / VHOST_LOG_CHUNK < dev->log_size);
for (;from < to; ++from) {
vhost_log_chunk_t log;
commit e314672a8a95f5dc98534f0682fce50fb83dbc5c
Author: Alex Williamson <alex.williamson at redhat.com>
Date: Fri Aug 13 09:54:52 2010 -0400
vhost: Fix size of dirty log sync on resize
When the vhost log is resized, we want to sync up to
the size of the old log. With that end address in place,
ignore regions that start after then end rather than
hitting assert.
This also addresses the following crash report:
When migrating a vm using vhost-net we hit the following assertion:
qemu-kvm: /usr/src/packages/BUILD/qemu-kvm-0.15.1/hw/vhost.c:30:
vhost_dev_sync_region: Assertion `start / (0x1000 * (8 *
sizeof(vhost_log_chunk_t))) < dev->log_size' failed.
The cases which the end < start check is intended to catch, such as
for vga video memory, will also likely trigger the assertion.
Reorder the code to handle this correctly.
Reported-by: Josh Durgin <josh.durgin at dreamhost.com>
Signed-off-by: Bruce Rogers <brogers at suse.com>
Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/vhost.c b/hw/vhost.c
index 8d3ba5b..7e282dd 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -31,11 +31,11 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
vhost_log_chunk_t *to = dev->log + end / VHOST_LOG_CHUNK + 1;
uint64_t addr = (start / VHOST_LOG_CHUNK) * VHOST_LOG_CHUNK;
- assert(end / VHOST_LOG_CHUNK < dev->log_size);
- assert(start / VHOST_LOG_CHUNK < dev->log_size);
if (end < start) {
return;
}
+ assert(end / VHOST_LOG_CHUNK < dev->log_size);
+
for (;from < to; ++from) {
vhost_log_chunk_t log;
int bit;
@@ -277,8 +277,9 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base);
assert(r >= 0);
for (i = 0; i < dev->n_mem_sections; ++i) {
- vhost_sync_dirty_bitmap(dev, &dev->mem_sections[i],
- 0, (target_phys_addr_t)~0x0ull);
+ /* Sync only the range covered by the old log */
+ vhost_sync_dirty_bitmap(dev, &dev->mem_sections[i], 0,
+ dev->log_size * VHOST_LOG_CHUNK - 1);
}
if (dev->log) {
g_free(dev->log);
commit d6c730086cbf24382eb8cff25551798769edfd84
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Mon Mar 26 11:26:16 2012 +0200
pc: reduce duplication in compat machine types
Make it easier to add compat properties, by
adding macros for properties duplicated across
machine types.
Note: there could be bugs in compat properties,
this patch does not attempt to address them,
the code is bug for bug identical to the original.
Tested by: generated a preprocessed file, sorted and
compared to sorted original.
Lightly tested on x86_64.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index fadca4c..0f61f00 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -359,50 +359,69 @@ static QEMUMachine pc_machine_v1_1 = {
.is_default = 1,
};
+#define PC_COMPAT_1_0 \
+ {\
+ .driver = "pc-sysfw",\
+ .property = "rom_only",\
+ .value = stringify(1),\
+ }, {\
+ .driver = "isa-fdc",\
+ .property = "check_media_rate",\
+ .value = "off",\
+ }
+
static QEMUMachine pc_machine_v1_0 = {
.name = "pc-1.0",
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- }, {
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },
+ PC_COMPAT_1_0,
{ /* end of list */ }
},
};
+#define PC_COMPAT_0_15 \
+ PC_COMPAT_1_0
+
static QEMUMachine pc_machine_v0_15 = {
.name = "pc-0.15",
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- }, {
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },
+ PC_COMPAT_0_15,
{ /* end of list */ }
},
};
+#define PC_COMPAT_0_14 \
+ PC_COMPAT_0_15,\
+ {\
+ .driver = "virtio-blk-pci",\
+ .property = "event_idx",\
+ .value = "off",\
+ },{\
+ .driver = "virtio-serial-pci",\
+ .property = "event_idx",\
+ .value = "off",\
+ },{\
+ .driver = "virtio-net-pci",\
+ .property = "event_idx",\
+ .value = "off",\
+ },{\
+ .driver = "virtio-balloon-pci",\
+ .property = "event_idx",\
+ .value = "off",\
+ }
+
static QEMUMachine pc_machine_v0_14 = {
.name = "pc-0.14",
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_14,
{
.driver = "qxl",
.property = "revision",
@@ -411,42 +430,30 @@ static QEMUMachine pc_machine_v0_14 = {
.driver = "qxl-vga",
.property = "revision",
.value = stringify(2),
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
},
{ /* end of list */ }
},
};
+#define PC_COMPAT_0_13 \
+ PC_COMPAT_0_14,\
+ {\
+ .driver = "PCI",\
+ .property = "command_serr_enable",\
+ .value = "off",\
+ },{\
+ .driver = "AC97",\
+ .property = "use_broken_id",\
+ .value = stringify(1),\
+ }
+
static QEMUMachine pc_machine_v0_13 = {
.name = "pc-0.13",
.desc = "Standard PC",
.init = pc_init_pci_no_kvmclock,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_13,
{
.driver = "virtio-9p-pci",
.property = "vectors",
@@ -459,59 +466,31 @@ static QEMUMachine pc_machine_v0_13 = {
.driver = "vmware-svga",
.property = "rombar",
.value = stringify(0),
- },{
- .driver = "PCI",
- .property = "command_serr_enable",
- .value = "off",
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "AC97",
- .property = "use_broken_id",
- .value = stringify(1),
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
},
{ /* end of list */ }
},
};
+#define PC_COMPAT_0_12 \
+ PC_COMPAT_0_13,\
+ {\
+ .driver = "virtio-serial-pci",\
+ .property = "max_ports",\
+ .value = stringify(1),\
+ },{\
+ .driver = "virtio-serial-pci",\
+ .property = "vectors",\
+ .value = stringify(0),\
+ }
+
static QEMUMachine pc_machine_v0_12 = {
.name = "pc-0.12",
.desc = "Standard PC",
.init = pc_init_pci_no_kvmclock,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_12,
{
- .driver = "virtio-serial-pci",
- .property = "max_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
.driver = "VGA",
.property = "rombar",
.value = stringify(0),
@@ -519,63 +498,27 @@ static QEMUMachine pc_machine_v0_12 = {
.driver = "vmware-svga",
.property = "rombar",
.value = stringify(0),
- },{
- .driver = "PCI",
- .property = "command_serr_enable",
- .value = "off",
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "AC97",
- .property = "use_broken_id",
- .value = stringify(1),
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
},
{ /* end of list */ }
}
};
+#define PC_COMPAT_0_11 \
+ PC_COMPAT_0_12,\
+ {\
+ .driver = "virtio-blk-pci",\
+ .property = "vectors",\
+ .value = stringify(0),\
+ }
+
static QEMUMachine pc_machine_v0_11 = {
.name = "pc-0.11",
.desc = "Standard PC, qemu 0.11",
.init = pc_init_pci_no_kvmclock,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_11,
{
- .driver = "virtio-blk-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "virtio-serial-pci",
- .property = "max_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
.driver = "ide-drive",
.property = "ver",
.value = "0.11",
@@ -583,43 +526,6 @@ static QEMUMachine pc_machine_v0_11 = {
.driver = "scsi-disk",
.property = "ver",
.value = "0.11",
- },{
- .driver = "PCI",
- .property = "rombar",
- .value = stringify(0),
- },{
- .driver = "PCI",
- .property = "command_serr_enable",
- .value = "off",
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "AC97",
- .property = "use_broken_id",
- .value = stringify(1),
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
},
{ /* end of list */ }
}
@@ -631,6 +537,7 @@ static QEMUMachine pc_machine_v0_10 = {
.init = pc_init_pci_no_kvmclock,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_11,
{
.driver = "virtio-blk-pci",
.property = "class",
@@ -640,22 +547,10 @@ static QEMUMachine pc_machine_v0_10 = {
.property = "class",
.value = stringify(PCI_CLASS_DISPLAY_OTHER),
},{
- .driver = "virtio-serial-pci",
- .property = "max_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
.driver = "virtio-net-pci",
.property = "vectors",
.value = stringify(0),
},{
- .driver = "virtio-blk-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
.driver = "ide-drive",
.property = "ver",
.value = "0.10",
@@ -663,43 +558,6 @@ static QEMUMachine pc_machine_v0_10 = {
.driver = "scsi-disk",
.property = "ver",
.value = "0.10",
- },{
- .driver = "PCI",
- .property = "rombar",
- .value = stringify(0),
- },{
- .driver = "PCI",
- .property = "command_serr_enable",
- .value = "off",
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "AC97",
- .property = "use_broken_id",
- .value = stringify(1),
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
},
{ /* end of list */ }
},
commit d50c6c8b0fc28c2dd91f3f7ab2a0bbb56419214b
Author: Alexey Korolev <alexey.korolev at endace.com>
Date: Wed Feb 29 14:35:14 2012 +1300
piix_pci: fix typo in i400FX chipset init code
There is a typo in i440FX init code. This is causing problems when
somebody wants to access the 64bit PCI range.
Signed-off-by: Alexey Korolev <alexey.korolev at endace.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 179d9a6..09e84f5 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -349,7 +349,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, isa_bus, pic,
address_space_mem, address_space_io, ram_size,
pci_hole_start, pci_hole_size,
- pci_hole64_size, pci_hole64_size,
+ pci_hole64_start, pci_hole64_size,
pci_memory, ram_memory);
return b;
}
commit c1958aea51a14199d05d392edce932a956e1674d
Author: Andreas Färber <afaerber at suse.de>
Date: Tue Apr 3 00:16:24 2012 +0200
target-i386: QOM'ify CPU reset
Move code from cpu_state_reset() into QOM x86_cpu_reset(),
fixing style issues for FPU init.
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index f4463e1..3df53ca 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1374,10 +1374,80 @@ static void x86_cpu_reset(CPUState *s)
X86CPU *cpu = X86_CPU(s);
X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
CPUX86State *env = &cpu->env;
+ int i;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
+ }
xcc->parent_reset(s);
- cpu_state_reset(env);
+
+ memset(env, 0, offsetof(CPUX86State, breakpoints));
+
+ tlb_flush(env, 1);
+
+ env->old_exception = -1;
+
+ /* init to reset state */
+
+#ifdef CONFIG_SOFTMMU
+ env->hflags |= HF_SOFTMMU_MASK;
+#endif
+ env->hflags2 |= HF2_GIF_MASK;
+
+ cpu_x86_update_cr0(env, 0x60000010);
+ env->a20_mask = ~0x0;
+ env->smbase = 0x30000;
+
+ env->idt.limit = 0xffff;
+ env->gdt.limit = 0xffff;
+ env->ldt.limit = 0xffff;
+ env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT);
+ env->tr.limit = 0xffff;
+ env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT);
+
+ cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
+ DESC_R_MASK | DESC_A_MASK);
+ cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+ DESC_A_MASK);
+ cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+ DESC_A_MASK);
+ cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+ DESC_A_MASK);
+ cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+ DESC_A_MASK);
+ cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+ DESC_A_MASK);
+
+ env->eip = 0xfff0;
+ env->regs[R_EDX] = env->cpuid_version;
+
+ env->eflags = 0x2;
+
+ /* FPU init */
+ for (i = 0; i < 8; i++) {
+ env->fptags[i] = 1;
+ }
+ env->fpuc = 0x37f;
+
+ env->mxcsr = 0x1f80;
+
+ env->pat = 0x0007040600070406ULL;
+ env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
+
+ memset(env->dr, 0, sizeof(env->dr));
+ env->dr[6] = DR6_FIXED_1;
+ env->dr[7] = DR7_FIXED_1;
+ cpu_breakpoint_remove_all(env, BP_CPU);
+ cpu_watchpoint_remove_all(env, BP_CPU);
}
static void mce_init(X86CPU *cpu)
diff --git a/target-i386/helper.c b/target-i386/helper.c
index d8ceee1..87954f0 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -29,76 +29,7 @@
/* NOTE: must be called outside the CPU execute loop */
void cpu_state_reset(CPUX86State *env)
{
- int i;
-
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
- }
-
- memset(env, 0, offsetof(CPUX86State, breakpoints));
-
- tlb_flush(env, 1);
-
- env->old_exception = -1;
-
- /* init to reset state */
-
-#ifdef CONFIG_SOFTMMU
- env->hflags |= HF_SOFTMMU_MASK;
-#endif
- env->hflags2 |= HF2_GIF_MASK;
-
- cpu_x86_update_cr0(env, 0x60000010);
- env->a20_mask = ~0x0;
- env->smbase = 0x30000;
-
- env->idt.limit = 0xffff;
- env->gdt.limit = 0xffff;
- env->ldt.limit = 0xffff;
- env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT);
- env->tr.limit = 0xffff;
- env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT);
-
- cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff,
- DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
- DESC_R_MASK | DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff,
- DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
- DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff,
- DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
- DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff,
- DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
- DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff,
- DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
- DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff,
- DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
- DESC_A_MASK);
-
- env->eip = 0xfff0;
- env->regs[R_EDX] = env->cpuid_version;
-
- env->eflags = 0x2;
-
- /* FPU init */
- for(i = 0;i < 8; i++)
- env->fptags[i] = 1;
- env->fpuc = 0x37f;
-
- env->mxcsr = 0x1f80;
-
- env->pat = 0x0007040600070406ULL;
- env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
-
- memset(env->dr, 0, sizeof(env->dr));
- env->dr[6] = DR6_FIXED_1;
- env->dr[7] = DR7_FIXED_1;
- cpu_breakpoint_remove_all(env, BP_CPU);
- cpu_watchpoint_remove_all(env, BP_CPU);
+ cpu_reset(ENV_GET_CPU(env));
}
static void cpu_x86_version(CPUX86State *env, int *family, int *model)
commit de024815e3b523addf58f1f79846b7fe74643678
Author: Andreas Färber <afaerber at suse.de>
Date: Tue Apr 3 00:00:17 2012 +0200
target-i386: QOM'ify CPU init
Move code from cpu_x86_init() to new QOM x86_cpu_initfn().
Also move mce_init() to cpu.c since it's used nowhere else.
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 36790da..f4463e1 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1380,6 +1380,32 @@ static void x86_cpu_reset(CPUState *s)
cpu_state_reset(env);
}
+static void mce_init(X86CPU *cpu)
+{
+ CPUX86State *cenv = &cpu->env;
+ unsigned int bank;
+
+ if (((cenv->cpuid_version >> 8) & 0xf) >= 6
+ && (cenv->cpuid_features & (CPUID_MCE | CPUID_MCA)) ==
+ (CPUID_MCE | CPUID_MCA)) {
+ cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
+ cenv->mcg_ctl = ~(uint64_t)0;
+ for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
+ cenv->mce_banks[bank * 4] = ~(uint64_t)0;
+ }
+ }
+}
+
+static void x86_cpu_initfn(Object *obj)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+
+ cpu_exec_init(env);
+ env->cpuid_apic_id = env->cpu_index;
+ mce_init(cpu);
+}
+
static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
{
X86CPUClass *xcc = X86_CPU_CLASS(oc);
@@ -1393,6 +1419,7 @@ static const TypeInfo x86_cpu_type_info = {
.name = TYPE_X86_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(X86CPU),
+ .instance_init = x86_cpu_initfn,
.abstract = false,
.class_size = sizeof(X86CPUClass),
.class_init = x86_cpu_common_class_init,
diff --git a/target-i386/helper.c b/target-i386/helper.c
index fb87975..d8ceee1 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1197,21 +1197,6 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access)
}
#endif /* !CONFIG_USER_ONLY */
-static void mce_init(CPUX86State *cenv)
-{
- unsigned int bank;
-
- if (((cenv->cpuid_version >> 8) & 0xf) >= 6
- && (cenv->cpuid_features & (CPUID_MCE | CPUID_MCA)) ==
- (CPUID_MCE | CPUID_MCA)) {
- cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
- cenv->mcg_ctl = ~(uint64_t)0;
- for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
- cenv->mce_banks[bank * 4] = ~(uint64_t)0;
- }
- }
-}
-
int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
target_ulong *base, unsigned int *limit,
unsigned int *flags)
@@ -1249,7 +1234,6 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
cpu = X86_CPU(object_new(TYPE_X86_CPU));
env = &cpu->env;
- cpu_exec_init(env);
env->cpu_model_str = cpu_model;
/* init various static tables used in TCG mode */
@@ -1265,8 +1249,6 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
object_delete(OBJECT(cpu));
return NULL;
}
- env->cpuid_apic_id = env->cpu_index;
- mce_init(env);
qemu_init_vcpu(env);
commit 5fd2087a1b7b3075828de741d76188441ee35bc8
Author: Andreas Färber <afaerber at suse.de>
Date: Mon Apr 2 23:20:08 2012 +0200
target-i386: QOM'ify CPU
Embed CPUX86State as first member of X86CPU.
Distinguish between "x86_64-cpu" and "i386-cpu".
Drop cpu_x86_close() in favor of calling object_delete() directly.
For now let CPUClass::reset() call cpu_state_reset().
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
new file mode 100644
index 0000000..40635c4
--- /dev/null
+++ b/target-i386/cpu-qom.h
@@ -0,0 +1,75 @@
+/*
+ * QEMU x86 CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_I386_CPU_QOM_H
+#define QEMU_I386_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#ifdef TARGET_X86_64
+#define TYPE_X86_CPU "x86_64-cpu"
+#else
+#define TYPE_X86_CPU "i386-cpu"
+#endif
+
+#define X86_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(X86CPUClass, (klass), TYPE_X86_CPU)
+#define X86_CPU(obj) \
+ OBJECT_CHECK(X86CPU, (obj), TYPE_X86_CPU)
+#define X86_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(X86CPUClass, (obj), TYPE_X86_CPU)
+
+/**
+ * X86CPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An x86 CPU model or family.
+ */
+typedef struct X86CPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} X86CPUClass;
+
+/**
+ * X86CPU:
+ * @env: #CPUX86State
+ *
+ * An x86 CPU.
+ */
+typedef struct X86CPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUX86State env;
+} X86CPU;
+
+static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
+{
+ return X86_CPU(container_of(env, X86CPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(x86_env_get_cpu(e))
+
+
+#endif
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 465ea15..36790da 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1367,3 +1367,40 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
}
}
+
+/* CPUClass::reset() */
+static void x86_cpu_reset(CPUState *s)
+{
+ X86CPU *cpu = X86_CPU(s);
+ X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
+ CPUX86State *env = &cpu->env;
+
+ xcc->parent_reset(s);
+
+ cpu_state_reset(env);
+}
+
+static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
+{
+ X86CPUClass *xcc = X86_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
+
+ xcc->parent_reset = cc->reset;
+ cc->reset = x86_cpu_reset;
+}
+
+static const TypeInfo x86_cpu_type_info = {
+ .name = TYPE_X86_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(X86CPU),
+ .abstract = false,
+ .class_size = sizeof(X86CPUClass),
+ .class_init = x86_cpu_common_class_init,
+};
+
+static void x86_cpu_register_types(void)
+{
+ type_register_static(&x86_cpu_type_info);
+}
+
+type_init(x86_cpu_register_types)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index a1ed3e7..4bb4592 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -783,9 +783,10 @@ typedef struct CPUX86State {
TPRAccess tpr_access_type;
} CPUX86State;
+#include "cpu-qom.h"
+
CPUX86State *cpu_x86_init(const char *cpu_model);
int cpu_x86_exec(CPUX86State *s);
-void cpu_x86_close(CPUX86State *s);
void x86_cpu_list (FILE *f, fprintf_function cpu_fprintf, const char *optarg);
void x86_cpudef_setup(void);
int cpu_x86_support_mca_broadcast(CPUX86State *env);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 83122bf..fb87975 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -101,11 +101,6 @@ void cpu_state_reset(CPUX86State *env)
cpu_watchpoint_remove_all(env, BP_CPU);
}
-void cpu_x86_close(CPUX86State *env)
-{
- g_free(env);
-}
-
static void cpu_x86_version(CPUX86State *env, int *family, int *model)
{
int cpuver = env->cpuid_version;
@@ -1248,10 +1243,12 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
CPUX86State *cpu_x86_init(const char *cpu_model)
{
+ X86CPU *cpu;
CPUX86State *env;
static int inited;
- env = g_malloc0(sizeof(CPUX86State));
+ cpu = X86_CPU(object_new(TYPE_X86_CPU));
+ env = &cpu->env;
cpu_exec_init(env);
env->cpu_model_str = cpu_model;
@@ -1265,7 +1262,7 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
#endif
}
if (cpu_x86_register(env, cpu_model) < 0) {
- cpu_x86_close(env);
+ object_delete(OBJECT(cpu));
return NULL;
}
env->cpuid_apic_id = env->cpu_index;
commit 30471bc94e1eb4ce1c87a56b6210a3baa1698d58
Author: Andreas Färber <afaerber at suse.de>
Date: Mon Apr 2 22:22:12 2012 +0200
target-i386: Rename cpuid.c
Name it cpu.c to align with other QOM'ified targets.
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/Makefile.target b/Makefile.target
index 14c8fa1..1110796 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -87,7 +87,7 @@ endif
endif
libobj-y += helper.o
ifeq ($(TARGET_BASE_ARCH), i386)
-libobj-y += cpuid.o
+libobj-y += cpu.o
endif
libobj-$(TARGET_SPARC64) += vis_helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
new file mode 100644
index 0000000..465ea15
--- /dev/null
+++ b/target-i386/cpu.c
@@ -0,0 +1,1369 @@
+/*
+ * i386 CPUID helper functions
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "kvm.h"
+
+#include "qemu-option.h"
+#include "qemu-config.h"
+
+#include "hyperv.h"
+
+/* feature flags taken from "Intel Processor Identification and the CPUID
+ * Instruction" and AMD's "CPUID Specification". In cases of disagreement
+ * between feature naming conventions, aliases may be added.
+ */
+static const char *feature_name[] = {
+ "fpu", "vme", "de", "pse",
+ "tsc", "msr", "pae", "mce",
+ "cx8", "apic", NULL, "sep",
+ "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
+ NULL, "ds" /* Intel dts */, "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss",
+ "ht" /* Intel htt */, "tm", "ia64", "pbe",
+};
+static const char *ext_feature_name[] = {
+ "pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor",
+ "ds_cpl", "vmx", "smx", "est",
+ "tm2", "ssse3", "cid", NULL,
+ "fma", "cx16", "xtpr", "pdcm",
+ NULL, NULL, "dca", "sse4.1|sse4_1",
+ "sse4.2|sse4_2", "x2apic", "movbe", "popcnt",
+ "tsc-deadline", "aes", "xsave", "osxsave",
+ "avx", NULL, NULL, "hypervisor",
+};
+static const char *ext2_feature_name[] = {
+ "fpu", "vme", "de", "pse",
+ "tsc", "msr", "pae", "mce",
+ "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall",
+ "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", NULL, NULL /* Linux mp */,
+ "nx|xd", NULL, "mmxext", "mmx",
+ "fxsr", "fxsr_opt|ffxsr", "pdpe1gb" /* AMD Page1GB */, "rdtscp",
+ NULL, "lm|i64", "3dnowext", "3dnow",
+};
+static const char *ext3_feature_name[] = {
+ "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
+ "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
+ "3dnowprefetch", "osvw", "ibs", "xop",
+ "skinit", "wdt", NULL, NULL,
+ "fma4", NULL, "cvt16", "nodeid_msr",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+};
+
+static const char *kvm_feature_name[] = {
+ "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static const char *svm_feature_name[] = {
+ "npt", "lbrv", "svm_lock", "nrip_save",
+ "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists",
+ NULL, NULL, "pause_filter", NULL,
+ "pfthreshold", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+};
+
+/* collects per-function cpuid data
+ */
+typedef struct model_features_t {
+ uint32_t *guest_feat;
+ uint32_t *host_feat;
+ uint32_t check_feat;
+ const char **flag_names;
+ uint32_t cpuid;
+ } model_features_t;
+
+int check_cpuid = 0;
+int enforce_cpuid = 0;
+
+void host_cpuid(uint32_t function, uint32_t count,
+ uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
+{
+#if defined(CONFIG_KVM)
+ uint32_t vec[4];
+
+#ifdef __x86_64__
+ asm volatile("cpuid"
+ : "=a"(vec[0]), "=b"(vec[1]),
+ "=c"(vec[2]), "=d"(vec[3])
+ : "0"(function), "c"(count) : "cc");
+#else
+ asm volatile("pusha \n\t"
+ "cpuid \n\t"
+ "mov %%eax, 0(%2) \n\t"
+ "mov %%ebx, 4(%2) \n\t"
+ "mov %%ecx, 8(%2) \n\t"
+ "mov %%edx, 12(%2) \n\t"
+ "popa"
+ : : "a"(function), "c"(count), "S"(vec)
+ : "memory", "cc");
+#endif
+
+ if (eax)
+ *eax = vec[0];
+ if (ebx)
+ *ebx = vec[1];
+ if (ecx)
+ *ecx = vec[2];
+ if (edx)
+ *edx = vec[3];
+#endif
+}
+
+#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
+
+/* general substring compare of *[s1..e1) and *[s2..e2). sx is start of
+ * a substring. ex if !NULL points to the first char after a substring,
+ * otherwise the string is assumed to sized by a terminating nul.
+ * Return lexical ordering of *s1:*s2.
+ */
+static int sstrcmp(const char *s1, const char *e1, const char *s2,
+ const char *e2)
+{
+ for (;;) {
+ if (!*s1 || !*s2 || *s1 != *s2)
+ return (*s1 - *s2);
+ ++s1, ++s2;
+ if (s1 == e1 && s2 == e2)
+ return (0);
+ else if (s1 == e1)
+ return (*s2);
+ else if (s2 == e2)
+ return (*s1);
+ }
+}
+
+/* compare *[s..e) to *altstr. *altstr may be a simple string or multiple
+ * '|' delimited (possibly empty) strings in which case search for a match
+ * within the alternatives proceeds left to right. Return 0 for success,
+ * non-zero otherwise.
+ */
+static int altcmp(const char *s, const char *e, const char *altstr)
+{
+ const char *p, *q;
+
+ for (q = p = altstr; ; ) {
+ while (*p && *p != '|')
+ ++p;
+ if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p)))
+ return (0);
+ if (!*p)
+ return (1);
+ else
+ q = ++p;
+ }
+}
+
+/* search featureset for flag *[s..e), if found set corresponding bit in
+ * *pval and return true, otherwise return false
+ */
+static bool lookup_feature(uint32_t *pval, const char *s, const char *e,
+ const char **featureset)
+{
+ uint32_t mask;
+ const char **ppc;
+ bool found = false;
+
+ for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) {
+ if (*ppc && !altcmp(s, e, *ppc)) {
+ *pval |= mask;
+ found = true;
+ }
+ }
+ return found;
+}
+
+static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
+ uint32_t *ext_features,
+ uint32_t *ext2_features,
+ uint32_t *ext3_features,
+ uint32_t *kvm_features,
+ uint32_t *svm_features)
+{
+ if (!lookup_feature(features, flagname, NULL, feature_name) &&
+ !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
+ !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
+ !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
+ !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name) &&
+ !lookup_feature(svm_features, flagname, NULL, svm_feature_name))
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+typedef struct x86_def_t {
+ struct x86_def_t *next;
+ const char *name;
+ uint32_t level;
+ uint32_t vendor1, vendor2, vendor3;
+ int family;
+ int model;
+ int stepping;
+ int tsc_khz;
+ uint32_t features, ext_features, ext2_features, ext3_features;
+ uint32_t kvm_features, svm_features;
+ uint32_t xlevel;
+ char model_id[48];
+ int vendor_override;
+ uint32_t flags;
+ /* Store the results of Centaur's CPUID instructions */
+ uint32_t ext4_features;
+ uint32_t xlevel2;
+} x86_def_t;
+
+#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
+#define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
+ CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX | CPUID_APIC)
+#define PENTIUM2_FEATURES (PENTIUM_FEATURES | CPUID_PAE | CPUID_SEP | \
+ CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
+ CPUID_PSE36 | CPUID_FXSR)
+#define PENTIUM3_FEATURES (PENTIUM2_FEATURES | CPUID_SSE)
+#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
+ CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
+ CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
+ CPUID_PAE | CPUID_SEP | CPUID_APIC)
+#define EXT2_FEATURE_MASK 0x0183F3FF
+
+#define TCG_FEATURES (CPUID_FP87 | CPUID_PSE | CPUID_TSC | CPUID_MSR | \
+ CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \
+ CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
+ CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \
+ CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS)
+ /* partly implemented:
+ CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64)
+ CPUID_PSE36 (needed for Solaris) */
+ /* missing:
+ CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
+#define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | \
+ CPUID_EXT_CX16 | CPUID_EXT_POPCNT | \
+ CPUID_EXT_HYPERVISOR)
+ /* missing:
+ CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST,
+ CPUID_EXT_TM2, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_XSAVE */
+#define TCG_EXT2_FEATURES ((TCG_FEATURES & EXT2_FEATURE_MASK) | \
+ CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \
+ CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT)
+ /* missing:
+ CPUID_EXT2_PDPE1GB */
+#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
+ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
+#define TCG_SVM_FEATURES 0
+
+/* maintains list of cpu model definitions
+ */
+static x86_def_t *x86_defs = {NULL};
+
+/* built-in cpu model definitions (deprecated)
+ */
+static x86_def_t builtin_x86_defs[] = {
+ {
+ .name = "qemu64",
+ .level = 4,
+ .vendor1 = CPUID_VENDOR_AMD_1,
+ .vendor2 = CPUID_VENDOR_AMD_2,
+ .vendor3 = CPUID_VENDOR_AMD_3,
+ .family = 6,
+ .model = 2,
+ .stepping = 3,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+ CPUID_PSE36,
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
+ .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
+ CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
+ .xlevel = 0x8000000A,
+ .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
+ },
+ {
+ .name = "phenom",
+ .level = 5,
+ .vendor1 = CPUID_VENDOR_AMD_1,
+ .vendor2 = CPUID_VENDOR_AMD_2,
+ .vendor3 = CPUID_VENDOR_AMD_3,
+ .family = 16,
+ .model = 2,
+ .stepping = 3,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+ CPUID_PSE36 | CPUID_VME | CPUID_HT,
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
+ CPUID_EXT_POPCNT,
+ .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
+ CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
+ CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP,
+ /* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
+ CPUID_EXT3_CR8LEG,
+ CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
+ CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
+ .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
+ CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
+ .svm_features = CPUID_SVM_NPT | CPUID_SVM_LBRV,
+ .xlevel = 0x8000001A,
+ .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
+ },
+ {
+ .name = "core2duo",
+ .level = 10,
+ .family = 6,
+ .model = 15,
+ .stepping = 11,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+ CPUID_PSE36 | CPUID_VME | CPUID_DTS | CPUID_ACPI | CPUID_SS |
+ CPUID_HT | CPUID_TM | CPUID_PBE,
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
+ CPUID_EXT_DTES64 | CPUID_EXT_DSCPL | CPUID_EXT_VMX | CPUID_EXT_EST |
+ CPUID_EXT_TM2 | CPUID_EXT_CX16 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
+ .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .ext3_features = CPUID_EXT3_LAHF_LM,
+ .xlevel = 0x80000008,
+ .model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz",
+ },
+ {
+ .name = "kvm64",
+ .level = 5,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
+ .family = 15,
+ .model = 6,
+ .stepping = 1,
+ /* Missing: CPUID_VME, CPUID_HT */
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+ CPUID_PSE36,
+ /* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
+ /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
+ .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ /* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
+ CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
+ CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
+ CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */
+ .ext3_features = 0,
+ .xlevel = 0x80000008,
+ .model_id = "Common KVM processor"
+ },
+ {
+ .name = "qemu32",
+ .level = 4,
+ .family = 6,
+ .model = 3,
+ .stepping = 3,
+ .features = PPRO_FEATURES,
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
+ .xlevel = 0x80000004,
+ .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
+ },
+ {
+ .name = "kvm32",
+ .level = 5,
+ .family = 15,
+ .model = 6,
+ .stepping = 1,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36,
+ .ext_features = CPUID_EXT_SSE3,
+ .ext2_features = PPRO_FEATURES & EXT2_FEATURE_MASK,
+ .ext3_features = 0,
+ .xlevel = 0x80000008,
+ .model_id = "Common 32-bit KVM processor"
+ },
+ {
+ .name = "coreduo",
+ .level = 10,
+ .family = 6,
+ .model = 14,
+ .stepping = 8,
+ .features = PPRO_FEATURES | CPUID_VME |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_DTS | CPUID_ACPI |
+ CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_VMX |
+ CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
+ .ext2_features = CPUID_EXT2_NX,
+ .xlevel = 0x80000008,
+ .model_id = "Genuine Intel(R) CPU T2600 @ 2.16GHz",
+ },
+ {
+ .name = "486",
+ .level = 1,
+ .family = 4,
+ .model = 0,
+ .stepping = 0,
+ .features = I486_FEATURES,
+ .xlevel = 0,
+ },
+ {
+ .name = "pentium",
+ .level = 1,
+ .family = 5,
+ .model = 4,
+ .stepping = 3,
+ .features = PENTIUM_FEATURES,
+ .xlevel = 0,
+ },
+ {
+ .name = "pentium2",
+ .level = 2,
+ .family = 6,
+ .model = 5,
+ .stepping = 2,
+ .features = PENTIUM2_FEATURES,
+ .xlevel = 0,
+ },
+ {
+ .name = "pentium3",
+ .level = 2,
+ .family = 6,
+ .model = 7,
+ .stepping = 3,
+ .features = PENTIUM3_FEATURES,
+ .xlevel = 0,
+ },
+ {
+ .name = "athlon",
+ .level = 2,
+ .vendor1 = CPUID_VENDOR_AMD_1,
+ .vendor2 = CPUID_VENDOR_AMD_2,
+ .vendor3 = CPUID_VENDOR_AMD_3,
+ .family = 6,
+ .model = 2,
+ .stepping = 3,
+ .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA,
+ .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
+ .xlevel = 0x80000008,
+ /* XXX: put another string ? */
+ .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
+ },
+ {
+ .name = "n270",
+ /* original is on level 10 */
+ .level = 5,
+ .family = 6,
+ .model = 28,
+ .stepping = 2,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME | CPUID_DTS |
+ CPUID_ACPI | CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
+ /* Some CPUs got no CPUID_SEP */
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
+ CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR,
+ .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) | CPUID_EXT2_NX,
+ .ext3_features = CPUID_EXT3_LAHF_LM,
+ .xlevel = 0x8000000A,
+ .model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz",
+ },
+};
+
+static int cpu_x86_fill_model_id(char *str)
+{
+ uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
+ memcpy(str + i * 16 + 0, &eax, 4);
+ memcpy(str + i * 16 + 4, &ebx, 4);
+ memcpy(str + i * 16 + 8, &ecx, 4);
+ memcpy(str + i * 16 + 12, &edx, 4);
+ }
+ return 0;
+}
+
+static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
+{
+ uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+
+ x86_cpu_def->name = "host";
+ host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->level = eax;
+ x86_cpu_def->vendor1 = ebx;
+ x86_cpu_def->vendor2 = edx;
+ x86_cpu_def->vendor3 = ecx;
+
+ host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+ x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+ x86_cpu_def->stepping = eax & 0x0F;
+ x86_cpu_def->ext_features = ecx;
+ x86_cpu_def->features = edx;
+
+ host_cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->xlevel = eax;
+
+ host_cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->ext2_features = edx;
+ x86_cpu_def->ext3_features = ecx;
+ cpu_x86_fill_model_id(x86_cpu_def->model_id);
+ x86_cpu_def->vendor_override = 0;
+
+ /* Call Centaur's CPUID instruction. */
+ if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
+ x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
+ x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
+ host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
+ if (eax >= 0xC0000001) {
+ /* Support VIA max extended level */
+ x86_cpu_def->xlevel2 = eax;
+ host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->ext4_features = edx;
+ }
+ }
+
+ /*
+ * Every SVM feature requires emulation support in KVM - so we can't just
+ * read the host features here. KVM might even support SVM features not
+ * available on the host hardware. Just set all bits and mask out the
+ * unsupported ones later.
+ */
+ x86_cpu_def->svm_features = -1;
+
+ return 0;
+}
+
+static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
+{
+ int i;
+
+ for (i = 0; i < 32; ++i)
+ if (1 << i & mask) {
+ fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
+ " flag '%s' [0x%08x]\n",
+ f->cpuid >> 16, f->cpuid & 0xffff,
+ f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
+ break;
+ }
+ return 0;
+}
+
+/* best effort attempt to inform user requested cpu flags aren't making
+ * their way to the guest. Note: ft[].check_feat ideally should be
+ * specified via a guest_def field to suppress report of extraneous flags.
+ */
+static int check_features_against_host(x86_def_t *guest_def)
+{
+ x86_def_t host_def;
+ uint32_t mask;
+ int rv, i;
+ struct model_features_t ft[] = {
+ {&guest_def->features, &host_def.features,
+ ~0, feature_name, 0x00000000},
+ {&guest_def->ext_features, &host_def.ext_features,
+ ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
+ {&guest_def->ext2_features, &host_def.ext2_features,
+ ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
+ {&guest_def->ext3_features, &host_def.ext3_features,
+ ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
+
+ cpu_x86_fill_host(&host_def);
+ for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i)
+ for (mask = 1; mask; mask <<= 1)
+ if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
+ !(*ft[i].host_feat & mask)) {
+ unavailable_host_feature(&ft[i], mask);
+ rv = 1;
+ }
+ return rv;
+}
+
+static void x86_cpuid_version_set_family(CPUX86State *env, int family)
+{
+ env->cpuid_version &= ~0xff00f00;
+ if (family > 0x0f) {
+ env->cpuid_version |= 0xf00 | ((family - 0x0f) << 20);
+ } else {
+ env->cpuid_version |= family << 8;
+ }
+}
+
+static void x86_cpuid_version_set_model(CPUX86State *env, int model)
+{
+ env->cpuid_version &= ~0xf00f0;
+ env->cpuid_version |= ((model & 0xf) << 4) | ((model >> 4) << 16);
+}
+
+static void x86_cpuid_version_set_stepping(CPUX86State *env, int stepping)
+{
+ env->cpuid_version &= ~0xf;
+ env->cpuid_version |= stepping & 0xf;
+}
+
+static void x86_cpuid_set_model_id(CPUX86State *env, const char *model_id)
+{
+ int c, len, i;
+
+ if (model_id == NULL) {
+ model_id = "";
+ }
+ len = strlen(model_id);
+ for (i = 0; i < 48; i++) {
+ if (i >= len) {
+ c = '\0';
+ } else {
+ c = (uint8_t)model_id[i];
+ }
+ env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
+ }
+}
+
+static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
+{
+ unsigned int i;
+ x86_def_t *def;
+
+ char *s = g_strdup(cpu_model);
+ char *featurestr, *name = strtok(s, ",");
+ /* Features to be added*/
+ uint32_t plus_features = 0, plus_ext_features = 0;
+ uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
+ uint32_t plus_kvm_features = 0, plus_svm_features = 0;
+ /* Features to be removed */
+ uint32_t minus_features = 0, minus_ext_features = 0;
+ uint32_t minus_ext2_features = 0, minus_ext3_features = 0;
+ uint32_t minus_kvm_features = 0, minus_svm_features = 0;
+ uint32_t numvalue;
+
+ for (def = x86_defs; def; def = def->next)
+ if (name && !strcmp(name, def->name))
+ break;
+ if (kvm_enabled() && name && strcmp(name, "host") == 0) {
+ cpu_x86_fill_host(x86_cpu_def);
+ } else if (!def) {
+ goto error;
+ } else {
+ memcpy(x86_cpu_def, def, sizeof(*def));
+ }
+
+ plus_kvm_features = ~0; /* not supported bits will be filtered out later */
+
+ add_flagname_to_bitmaps("hypervisor", &plus_features,
+ &plus_ext_features, &plus_ext2_features, &plus_ext3_features,
+ &plus_kvm_features, &plus_svm_features);
+
+ featurestr = strtok(NULL, ",");
+
+ while (featurestr) {
+ char *val;
+ if (featurestr[0] == '+') {
+ add_flagname_to_bitmaps(featurestr + 1, &plus_features,
+ &plus_ext_features, &plus_ext2_features,
+ &plus_ext3_features, &plus_kvm_features,
+ &plus_svm_features);
+ } else if (featurestr[0] == '-') {
+ add_flagname_to_bitmaps(featurestr + 1, &minus_features,
+ &minus_ext_features, &minus_ext2_features,
+ &minus_ext3_features, &minus_kvm_features,
+ &minus_svm_features);
+ } else if ((val = strchr(featurestr, '='))) {
+ *val = 0; val++;
+ if (!strcmp(featurestr, "family")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ x86_cpu_def->family = numvalue;
+ } else if (!strcmp(featurestr, "model")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err || numvalue > 0xff) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ x86_cpu_def->model = numvalue;
+ } else if (!strcmp(featurestr, "stepping")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err || numvalue > 0xf) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ x86_cpu_def->stepping = numvalue ;
+ } else if (!strcmp(featurestr, "level")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ x86_cpu_def->level = numvalue;
+ } else if (!strcmp(featurestr, "xlevel")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ if (numvalue < 0x80000000) {
+ numvalue += 0x80000000;
+ }
+ x86_cpu_def->xlevel = numvalue;
+ } else if (!strcmp(featurestr, "vendor")) {
+ if (strlen(val) != 12) {
+ fprintf(stderr, "vendor string must be 12 chars long\n");
+ goto error;
+ }
+ x86_cpu_def->vendor1 = 0;
+ x86_cpu_def->vendor2 = 0;
+ x86_cpu_def->vendor3 = 0;
+ for(i = 0; i < 4; i++) {
+ x86_cpu_def->vendor1 |= ((uint8_t)val[i ]) << (8 * i);
+ x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i);
+ x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i);
+ }
+ x86_cpu_def->vendor_override = 1;
+ } else if (!strcmp(featurestr, "model_id")) {
+ pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id),
+ val);
+ } else if (!strcmp(featurestr, "tsc_freq")) {
+ int64_t tsc_freq;
+ char *err;
+
+ tsc_freq = strtosz_suffix_unit(val, &err,
+ STRTOSZ_DEFSUFFIX_B, 1000);
+ if (tsc_freq < 0 || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ x86_cpu_def->tsc_khz = tsc_freq / 1000;
+ } else if (!strcmp(featurestr, "hv_spinlocks")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ hyperv_set_spinlock_retries(numvalue);
+ } else {
+ fprintf(stderr, "unrecognized feature %s\n", featurestr);
+ goto error;
+ }
+ } else if (!strcmp(featurestr, "check")) {
+ check_cpuid = 1;
+ } else if (!strcmp(featurestr, "enforce")) {
+ check_cpuid = enforce_cpuid = 1;
+ } else if (!strcmp(featurestr, "hv_relaxed")) {
+ hyperv_enable_relaxed_timing(true);
+ } else if (!strcmp(featurestr, "hv_vapic")) {
+ hyperv_enable_vapic_recommended(true);
+ } else {
+ fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
+ goto error;
+ }
+ featurestr = strtok(NULL, ",");
+ }
+ x86_cpu_def->features |= plus_features;
+ x86_cpu_def->ext_features |= plus_ext_features;
+ x86_cpu_def->ext2_features |= plus_ext2_features;
+ x86_cpu_def->ext3_features |= plus_ext3_features;
+ x86_cpu_def->kvm_features |= plus_kvm_features;
+ x86_cpu_def->svm_features |= plus_svm_features;
+ x86_cpu_def->features &= ~minus_features;
+ x86_cpu_def->ext_features &= ~minus_ext_features;
+ x86_cpu_def->ext2_features &= ~minus_ext2_features;
+ x86_cpu_def->ext3_features &= ~minus_ext3_features;
+ x86_cpu_def->kvm_features &= ~minus_kvm_features;
+ x86_cpu_def->svm_features &= ~minus_svm_features;
+ if (check_cpuid) {
+ if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
+ goto error;
+ }
+ g_free(s);
+ return 0;
+
+error:
+ g_free(s);
+ return -1;
+}
+
+/* generate a composite string into buf of all cpuid names in featureset
+ * selected by fbits. indicate truncation at bufsize in the event of overflow.
+ * if flags, suppress names undefined in featureset.
+ */
+static void listflags(char *buf, int bufsize, uint32_t fbits,
+ const char **featureset, uint32_t flags)
+{
+ const char **p = &featureset[31];
+ char *q, *b, bit;
+ int nc;
+
+ b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
+ *buf = '\0';
+ for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
+ if (fbits & 1 << bit && (*p || !flags)) {
+ if (*p)
+ nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
+ else
+ nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
+ if (bufsize <= nc) {
+ if (b) {
+ memcpy(b, "...", sizeof("..."));
+ }
+ return;
+ }
+ q += nc;
+ bufsize -= nc;
+ }
+}
+
+/* generate CPU information:
+ * -? list model names
+ * -?model list model names/IDs
+ * -?dump output all model (x86_def_t) data
+ * -?cpuid list all recognized cpuid flag names
+ */
+void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
+{
+ unsigned char model = !strcmp("?model", optarg);
+ unsigned char dump = !strcmp("?dump", optarg);
+ unsigned char cpuid = !strcmp("?cpuid", optarg);
+ x86_def_t *def;
+ char buf[256];
+
+ if (cpuid) {
+ (*cpu_fprintf)(f, "Recognized CPUID flags:\n");
+ listflags(buf, sizeof (buf), (uint32_t)~0, feature_name, 1);
+ (*cpu_fprintf)(f, " f_edx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext_feature_name, 1);
+ (*cpu_fprintf)(f, " f_ecx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext2_feature_name, 1);
+ (*cpu_fprintf)(f, " extf_edx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext3_feature_name, 1);
+ (*cpu_fprintf)(f, " extf_ecx: %s\n", buf);
+ return;
+ }
+ for (def = x86_defs; def; def = def->next) {
+ snprintf(buf, sizeof (buf), def->flags ? "[%s]": "%s", def->name);
+ if (model || dump) {
+ (*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
+ } else {
+ (*cpu_fprintf)(f, "x86 %16s\n", buf);
+ }
+ if (dump) {
+ memcpy(buf, &def->vendor1, sizeof (def->vendor1));
+ memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
+ memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
+ buf[12] = '\0';
+ (*cpu_fprintf)(f,
+ " family %d model %d stepping %d level %d xlevel 0x%x"
+ " vendor \"%s\"\n",
+ def->family, def->model, def->stepping, def->level,
+ def->xlevel, buf);
+ listflags(buf, sizeof (buf), def->features, feature_name, 0);
+ (*cpu_fprintf)(f, " feature_edx %08x (%s)\n", def->features,
+ buf);
+ listflags(buf, sizeof (buf), def->ext_features, ext_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " feature_ecx %08x (%s)\n", def->ext_features,
+ buf);
+ listflags(buf, sizeof (buf), def->ext2_features, ext2_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " extfeature_edx %08x (%s)\n",
+ def->ext2_features, buf);
+ listflags(buf, sizeof (buf), def->ext3_features, ext3_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " extfeature_ecx %08x (%s)\n",
+ def->ext3_features, buf);
+ (*cpu_fprintf)(f, "\n");
+ }
+ }
+ if (kvm_enabled()) {
+ (*cpu_fprintf)(f, "x86 %16s\n", "[host]");
+ }
+}
+
+int cpu_x86_register (CPUX86State *env, const char *cpu_model)
+{
+ x86_def_t def1, *def = &def1;
+
+ memset(def, 0, sizeof(*def));
+
+ if (cpu_x86_find_by_name(def, cpu_model) < 0)
+ return -1;
+ if (def->vendor1) {
+ env->cpuid_vendor1 = def->vendor1;
+ env->cpuid_vendor2 = def->vendor2;
+ env->cpuid_vendor3 = def->vendor3;
+ } else {
+ env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1;
+ env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2;
+ env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3;
+ }
+ env->cpuid_vendor_override = def->vendor_override;
+ env->cpuid_level = def->level;
+ x86_cpuid_version_set_family(env, def->family);
+ x86_cpuid_version_set_model(env, def->model);
+ x86_cpuid_version_set_stepping(env, def->stepping);
+ env->cpuid_features = def->features;
+ env->cpuid_ext_features = def->ext_features;
+ env->cpuid_ext2_features = def->ext2_features;
+ env->cpuid_ext3_features = def->ext3_features;
+ env->cpuid_xlevel = def->xlevel;
+ env->cpuid_kvm_features = def->kvm_features;
+ env->cpuid_svm_features = def->svm_features;
+ env->cpuid_ext4_features = def->ext4_features;
+ env->cpuid_xlevel2 = def->xlevel2;
+ env->tsc_khz = def->tsc_khz;
+ if (!kvm_enabled()) {
+ env->cpuid_features &= TCG_FEATURES;
+ env->cpuid_ext_features &= TCG_EXT_FEATURES;
+ env->cpuid_ext2_features &= (TCG_EXT2_FEATURES
+#ifdef TARGET_X86_64
+ | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM
+#endif
+ );
+ env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
+ env->cpuid_svm_features &= TCG_SVM_FEATURES;
+ }
+ x86_cpuid_set_model_id(env, def->model_id);
+ return 0;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* copy vendor id string to 32 bit register, nul pad as needed
+ */
+static void cpyid(const char *s, uint32_t *id)
+{
+ char *d = (char *)id;
+ char i;
+
+ for (i = sizeof (*id); i--; )
+ *d++ = *s ? *s++ : '\0';
+}
+
+/* interpret radix and convert from string to arbitrary scalar,
+ * otherwise flag failure
+ */
+#define setscalar(pval, str, perr) \
+{ \
+ char *pend; \
+ unsigned long ul; \
+ \
+ ul = strtoul(str, &pend, 0); \
+ *str && !*pend ? (*pval = ul) : (*perr = 1); \
+}
+
+/* map cpuid options to feature bits, otherwise return failure
+ * (option tags in *str are delimited by whitespace)
+ */
+static void setfeatures(uint32_t *pval, const char *str,
+ const char **featureset, int *perr)
+{
+ const char *p, *q;
+
+ for (q = p = str; *p || *q; q = p) {
+ while (iswhite(*p))
+ q = ++p;
+ while (*p && !iswhite(*p))
+ ++p;
+ if (!*q && !*p)
+ return;
+ if (!lookup_feature(pval, q, p, featureset)) {
+ fprintf(stderr, "error: feature \"%.*s\" not available in set\n",
+ (int)(p - q), q);
+ *perr = 1;
+ return;
+ }
+ }
+}
+
+/* map config file options to x86_def_t form
+ */
+static int cpudef_setfield(const char *name, const char *str, void *opaque)
+{
+ x86_def_t *def = opaque;
+ int err = 0;
+
+ if (!strcmp(name, "name")) {
+ g_free((void *)def->name);
+ def->name = g_strdup(str);
+ } else if (!strcmp(name, "model_id")) {
+ strncpy(def->model_id, str, sizeof (def->model_id));
+ } else if (!strcmp(name, "level")) {
+ setscalar(&def->level, str, &err)
+ } else if (!strcmp(name, "vendor")) {
+ cpyid(&str[0], &def->vendor1);
+ cpyid(&str[4], &def->vendor2);
+ cpyid(&str[8], &def->vendor3);
+ } else if (!strcmp(name, "family")) {
+ setscalar(&def->family, str, &err)
+ } else if (!strcmp(name, "model")) {
+ setscalar(&def->model, str, &err)
+ } else if (!strcmp(name, "stepping")) {
+ setscalar(&def->stepping, str, &err)
+ } else if (!strcmp(name, "feature_edx")) {
+ setfeatures(&def->features, str, feature_name, &err);
+ } else if (!strcmp(name, "feature_ecx")) {
+ setfeatures(&def->ext_features, str, ext_feature_name, &err);
+ } else if (!strcmp(name, "extfeature_edx")) {
+ setfeatures(&def->ext2_features, str, ext2_feature_name, &err);
+ } else if (!strcmp(name, "extfeature_ecx")) {
+ setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
+ } else if (!strcmp(name, "xlevel")) {
+ setscalar(&def->xlevel, str, &err)
+ } else {
+ fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
+ return (1);
+ }
+ if (err) {
+ fprintf(stderr, "error: bad option value [%s = %s]\n", name, str);
+ return (1);
+ }
+ return (0);
+}
+
+/* register config file entry as x86_def_t
+ */
+static int cpudef_register(QemuOpts *opts, void *opaque)
+{
+ x86_def_t *def = g_malloc0(sizeof (x86_def_t));
+
+ qemu_opt_foreach(opts, cpudef_setfield, def, 1);
+ def->next = x86_defs;
+ x86_defs = def;
+ return (0);
+}
+
+void cpu_clear_apic_feature(CPUX86State *env)
+{
+ env->cpuid_features &= ~CPUID_APIC;
+}
+
+#endif /* !CONFIG_USER_ONLY */
+
+/* register "cpudef" models defined in configuration file. Here we first
+ * preload any built-in definitions
+ */
+void x86_cpudef_setup(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
+ builtin_x86_defs[i].next = x86_defs;
+ builtin_x86_defs[i].flags = 1;
+ x86_defs = &builtin_x86_defs[i];
+ }
+#if !defined(CONFIG_USER_ONLY)
+ qemu_opts_foreach(qemu_find_opts("cpudef"), cpudef_register, NULL, 0);
+#endif
+}
+
+static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
+ uint32_t *ecx, uint32_t *edx)
+{
+ *ebx = env->cpuid_vendor1;
+ *edx = env->cpuid_vendor2;
+ *ecx = env->cpuid_vendor3;
+
+ /* sysenter isn't supported on compatibility mode on AMD, syscall
+ * isn't supported in compatibility mode on Intel.
+ * Normally we advertise the actual cpu vendor, but you can override
+ * this if you want to use KVM's sysenter/syscall emulation
+ * in compatibility mode and when doing cross vendor migration
+ */
+ if (kvm_enabled() && ! env->cpuid_vendor_override) {
+ host_cpuid(0, 0, NULL, ebx, ecx, edx);
+ }
+}
+
+void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
+ uint32_t *eax, uint32_t *ebx,
+ uint32_t *ecx, uint32_t *edx)
+{
+ /* test if maximum index reached */
+ if (index & 0x80000000) {
+ if (index > env->cpuid_xlevel) {
+ if (env->cpuid_xlevel2 > 0) {
+ /* Handle the Centaur's CPUID instruction. */
+ if (index > env->cpuid_xlevel2) {
+ index = env->cpuid_xlevel2;
+ } else if (index < 0xC0000000) {
+ index = env->cpuid_xlevel;
+ }
+ } else {
+ index = env->cpuid_xlevel;
+ }
+ }
+ } else {
+ if (index > env->cpuid_level)
+ index = env->cpuid_level;
+ }
+
+ switch(index) {
+ case 0:
+ *eax = env->cpuid_level;
+ get_cpuid_vendor(env, ebx, ecx, edx);
+ break;
+ case 1:
+ *eax = env->cpuid_version;
+ *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
+ *ecx = env->cpuid_ext_features;
+ *edx = env->cpuid_features;
+ if (env->nr_cores * env->nr_threads > 1) {
+ *ebx |= (env->nr_cores * env->nr_threads) << 16;
+ *edx |= 1 << 28; /* HTT bit */
+ }
+ break;
+ case 2:
+ /* cache info: needed for Pentium Pro compatibility */
+ *eax = 1;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0x2c307d;
+ break;
+ case 4:
+ /* cache info: needed for Core compatibility */
+ if (env->nr_cores > 1) {
+ *eax = (env->nr_cores - 1) << 26;
+ } else {
+ *eax = 0;
+ }
+ switch (count) {
+ case 0: /* L1 dcache info */
+ *eax |= 0x0000121;
+ *ebx = 0x1c0003f;
+ *ecx = 0x000003f;
+ *edx = 0x0000001;
+ break;
+ case 1: /* L1 icache info */
+ *eax |= 0x0000122;
+ *ebx = 0x1c0003f;
+ *ecx = 0x000003f;
+ *edx = 0x0000001;
+ break;
+ case 2: /* L2 cache info */
+ *eax |= 0x0000143;
+ if (env->nr_threads > 1) {
+ *eax |= (env->nr_threads - 1) << 14;
+ }
+ *ebx = 0x3c0003f;
+ *ecx = 0x0000fff;
+ *edx = 0x0000001;
+ break;
+ default: /* end of info */
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ }
+ break;
+ case 5:
+ /* mwait info: needed for Core compatibility */
+ *eax = 0; /* Smallest monitor-line size in bytes */
+ *ebx = 0; /* Largest monitor-line size in bytes */
+ *ecx = CPUID_MWAIT_EMX | CPUID_MWAIT_IBE;
+ *edx = 0;
+ break;
+ case 6:
+ /* Thermal and Power Leaf */
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ case 7:
+ if (kvm_enabled()) {
+ KVMState *s = env->kvm_state;
+
+ *eax = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EAX);
+ *ebx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EBX);
+ *ecx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_ECX);
+ *edx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EDX);
+ } else {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ }
+ break;
+ case 9:
+ /* Direct Cache Access Information Leaf */
+ *eax = 0; /* Bits 0-31 in DCA_CAP MSR */
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ case 0xA:
+ /* Architectural Performance Monitoring Leaf */
+ if (kvm_enabled()) {
+ KVMState *s = env->kvm_state;
+
+ *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX);
+ *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX);
+ *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX);
+ *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX);
+ } else {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ }
+ break;
+ case 0xD:
+ /* Processor Extended State */
+ if (!(env->cpuid_ext_features & CPUID_EXT_XSAVE)) {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ }
+ if (kvm_enabled()) {
+ KVMState *s = env->kvm_state;
+
+ *eax = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EAX);
+ *ebx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EBX);
+ *ecx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_ECX);
+ *edx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EDX);
+ } else {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ }
+ break;
+ case 0x80000000:
+ *eax = env->cpuid_xlevel;
+ *ebx = env->cpuid_vendor1;
+ *edx = env->cpuid_vendor2;
+ *ecx = env->cpuid_vendor3;
+ break;
+ case 0x80000001:
+ *eax = env->cpuid_version;
+ *ebx = 0;
+ *ecx = env->cpuid_ext3_features;
+ *edx = env->cpuid_ext2_features;
+
+ /* The Linux kernel checks for the CMPLegacy bit and
+ * discards multiple thread information if it is set.
+ * So dont set it here for Intel to make Linux guests happy.
+ */
+ if (env->nr_cores * env->nr_threads > 1) {
+ uint32_t tebx, tecx, tedx;
+ get_cpuid_vendor(env, &tebx, &tecx, &tedx);
+ if (tebx != CPUID_VENDOR_INTEL_1 ||
+ tedx != CPUID_VENDOR_INTEL_2 ||
+ tecx != CPUID_VENDOR_INTEL_3) {
+ *ecx |= 1 << 1; /* CmpLegacy bit */
+ }
+ }
+ break;
+ case 0x80000002:
+ case 0x80000003:
+ case 0x80000004:
+ *eax = env->cpuid_model[(index - 0x80000002) * 4 + 0];
+ *ebx = env->cpuid_model[(index - 0x80000002) * 4 + 1];
+ *ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2];
+ *edx = env->cpuid_model[(index - 0x80000002) * 4 + 3];
+ break;
+ case 0x80000005:
+ /* cache info (L1 cache) */
+ *eax = 0x01ff01ff;
+ *ebx = 0x01ff01ff;
+ *ecx = 0x40020140;
+ *edx = 0x40020140;
+ break;
+ case 0x80000006:
+ /* cache info (L2 cache) */
+ *eax = 0;
+ *ebx = 0x42004200;
+ *ecx = 0x02008140;
+ *edx = 0;
+ break;
+ case 0x80000008:
+ /* virtual & phys address size in low 2 bytes. */
+/* XXX: This value must match the one used in the MMU code. */
+ if (env->cpuid_ext2_features & CPUID_EXT2_LM) {
+ /* 64 bit processor */
+/* XXX: The physical address space is limited to 42 bits in exec.c. */
+ *eax = 0x00003028; /* 48 bits virtual, 40 bits physical */
+ } else {
+ if (env->cpuid_features & CPUID_PSE36)
+ *eax = 0x00000024; /* 36 bits physical */
+ else
+ *eax = 0x00000020; /* 32 bits physical */
+ }
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ if (env->nr_cores * env->nr_threads > 1) {
+ *ecx |= (env->nr_cores * env->nr_threads) - 1;
+ }
+ break;
+ case 0x8000000A:
+ if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
+ *eax = 0x00000001; /* SVM Revision */
+ *ebx = 0x00000010; /* nr of ASIDs */
+ *ecx = 0;
+ *edx = env->cpuid_svm_features; /* optional features */
+ } else {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ }
+ break;
+ case 0xC0000000:
+ *eax = env->cpuid_xlevel2;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ case 0xC0000001:
+ /* Support for VIA CPU's CPUID instruction */
+ *eax = env->cpuid_version;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = env->cpuid_ext4_features;
+ break;
+ case 0xC0000002:
+ case 0xC0000003:
+ case 0xC0000004:
+ /* Reserved for the future, and now filled with zero */
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ default:
+ /* reserved values: zero */
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ }
+}
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
deleted file mode 100644
index 465ea15..0000000
--- a/target-i386/cpuid.c
+++ /dev/null
@@ -1,1369 +0,0 @@
-/*
- * i386 CPUID helper functions
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "cpu.h"
-#include "kvm.h"
-
-#include "qemu-option.h"
-#include "qemu-config.h"
-
-#include "hyperv.h"
-
-/* feature flags taken from "Intel Processor Identification and the CPUID
- * Instruction" and AMD's "CPUID Specification". In cases of disagreement
- * between feature naming conventions, aliases may be added.
- */
-static const char *feature_name[] = {
- "fpu", "vme", "de", "pse",
- "tsc", "msr", "pae", "mce",
- "cx8", "apic", NULL, "sep",
- "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
- NULL, "ds" /* Intel dts */, "acpi", "mmx",
- "fxsr", "sse", "sse2", "ss",
- "ht" /* Intel htt */, "tm", "ia64", "pbe",
-};
-static const char *ext_feature_name[] = {
- "pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor",
- "ds_cpl", "vmx", "smx", "est",
- "tm2", "ssse3", "cid", NULL,
- "fma", "cx16", "xtpr", "pdcm",
- NULL, NULL, "dca", "sse4.1|sse4_1",
- "sse4.2|sse4_2", "x2apic", "movbe", "popcnt",
- "tsc-deadline", "aes", "xsave", "osxsave",
- "avx", NULL, NULL, "hypervisor",
-};
-static const char *ext2_feature_name[] = {
- "fpu", "vme", "de", "pse",
- "tsc", "msr", "pae", "mce",
- "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall",
- "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", NULL, NULL /* Linux mp */,
- "nx|xd", NULL, "mmxext", "mmx",
- "fxsr", "fxsr_opt|ffxsr", "pdpe1gb" /* AMD Page1GB */, "rdtscp",
- NULL, "lm|i64", "3dnowext", "3dnow",
-};
-static const char *ext3_feature_name[] = {
- "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
- "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
- "3dnowprefetch", "osvw", "ibs", "xop",
- "skinit", "wdt", NULL, NULL,
- "fma4", NULL, "cvt16", "nodeid_msr",
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
-};
-
-static const char *kvm_feature_name[] = {
- "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-};
-
-static const char *svm_feature_name[] = {
- "npt", "lbrv", "svm_lock", "nrip_save",
- "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists",
- NULL, NULL, "pause_filter", NULL,
- "pfthreshold", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
-};
-
-/* collects per-function cpuid data
- */
-typedef struct model_features_t {
- uint32_t *guest_feat;
- uint32_t *host_feat;
- uint32_t check_feat;
- const char **flag_names;
- uint32_t cpuid;
- } model_features_t;
-
-int check_cpuid = 0;
-int enforce_cpuid = 0;
-
-void host_cpuid(uint32_t function, uint32_t count,
- uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
-{
-#if defined(CONFIG_KVM)
- uint32_t vec[4];
-
-#ifdef __x86_64__
- asm volatile("cpuid"
- : "=a"(vec[0]), "=b"(vec[1]),
- "=c"(vec[2]), "=d"(vec[3])
- : "0"(function), "c"(count) : "cc");
-#else
- asm volatile("pusha \n\t"
- "cpuid \n\t"
- "mov %%eax, 0(%2) \n\t"
- "mov %%ebx, 4(%2) \n\t"
- "mov %%ecx, 8(%2) \n\t"
- "mov %%edx, 12(%2) \n\t"
- "popa"
- : : "a"(function), "c"(count), "S"(vec)
- : "memory", "cc");
-#endif
-
- if (eax)
- *eax = vec[0];
- if (ebx)
- *ebx = vec[1];
- if (ecx)
- *ecx = vec[2];
- if (edx)
- *edx = vec[3];
-#endif
-}
-
-#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
-
-/* general substring compare of *[s1..e1) and *[s2..e2). sx is start of
- * a substring. ex if !NULL points to the first char after a substring,
- * otherwise the string is assumed to sized by a terminating nul.
- * Return lexical ordering of *s1:*s2.
- */
-static int sstrcmp(const char *s1, const char *e1, const char *s2,
- const char *e2)
-{
- for (;;) {
- if (!*s1 || !*s2 || *s1 != *s2)
- return (*s1 - *s2);
- ++s1, ++s2;
- if (s1 == e1 && s2 == e2)
- return (0);
- else if (s1 == e1)
- return (*s2);
- else if (s2 == e2)
- return (*s1);
- }
-}
-
-/* compare *[s..e) to *altstr. *altstr may be a simple string or multiple
- * '|' delimited (possibly empty) strings in which case search for a match
- * within the alternatives proceeds left to right. Return 0 for success,
- * non-zero otherwise.
- */
-static int altcmp(const char *s, const char *e, const char *altstr)
-{
- const char *p, *q;
-
- for (q = p = altstr; ; ) {
- while (*p && *p != '|')
- ++p;
- if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p)))
- return (0);
- if (!*p)
- return (1);
- else
- q = ++p;
- }
-}
-
-/* search featureset for flag *[s..e), if found set corresponding bit in
- * *pval and return true, otherwise return false
- */
-static bool lookup_feature(uint32_t *pval, const char *s, const char *e,
- const char **featureset)
-{
- uint32_t mask;
- const char **ppc;
- bool found = false;
-
- for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) {
- if (*ppc && !altcmp(s, e, *ppc)) {
- *pval |= mask;
- found = true;
- }
- }
- return found;
-}
-
-static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
- uint32_t *ext_features,
- uint32_t *ext2_features,
- uint32_t *ext3_features,
- uint32_t *kvm_features,
- uint32_t *svm_features)
-{
- if (!lookup_feature(features, flagname, NULL, feature_name) &&
- !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
- !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
- !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
- !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name) &&
- !lookup_feature(svm_features, flagname, NULL, svm_feature_name))
- fprintf(stderr, "CPU feature %s not found\n", flagname);
-}
-
-typedef struct x86_def_t {
- struct x86_def_t *next;
- const char *name;
- uint32_t level;
- uint32_t vendor1, vendor2, vendor3;
- int family;
- int model;
- int stepping;
- int tsc_khz;
- uint32_t features, ext_features, ext2_features, ext3_features;
- uint32_t kvm_features, svm_features;
- uint32_t xlevel;
- char model_id[48];
- int vendor_override;
- uint32_t flags;
- /* Store the results of Centaur's CPUID instructions */
- uint32_t ext4_features;
- uint32_t xlevel2;
-} x86_def_t;
-
-#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
-#define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
- CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX | CPUID_APIC)
-#define PENTIUM2_FEATURES (PENTIUM_FEATURES | CPUID_PAE | CPUID_SEP | \
- CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
- CPUID_PSE36 | CPUID_FXSR)
-#define PENTIUM3_FEATURES (PENTIUM2_FEATURES | CPUID_SSE)
-#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
- CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
- CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
- CPUID_PAE | CPUID_SEP | CPUID_APIC)
-#define EXT2_FEATURE_MASK 0x0183F3FF
-
-#define TCG_FEATURES (CPUID_FP87 | CPUID_PSE | CPUID_TSC | CPUID_MSR | \
- CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \
- CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
- CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \
- CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS)
- /* partly implemented:
- CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64)
- CPUID_PSE36 (needed for Solaris) */
- /* missing:
- CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
-#define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | \
- CPUID_EXT_CX16 | CPUID_EXT_POPCNT | \
- CPUID_EXT_HYPERVISOR)
- /* missing:
- CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST,
- CPUID_EXT_TM2, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_XSAVE */
-#define TCG_EXT2_FEATURES ((TCG_FEATURES & EXT2_FEATURE_MASK) | \
- CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \
- CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT)
- /* missing:
- CPUID_EXT2_PDPE1GB */
-#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
- CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
-#define TCG_SVM_FEATURES 0
-
-/* maintains list of cpu model definitions
- */
-static x86_def_t *x86_defs = {NULL};
-
-/* built-in cpu model definitions (deprecated)
- */
-static x86_def_t builtin_x86_defs[] = {
- {
- .name = "qemu64",
- .level = 4,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
- .family = 6,
- .model = 2,
- .stepping = 3,
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- CPUID_PSE36,
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
- .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
- CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
- .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
- CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
- .xlevel = 0x8000000A,
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
- },
- {
- .name = "phenom",
- .level = 5,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
- .family = 16,
- .model = 2,
- .stepping = 3,
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- CPUID_PSE36 | CPUID_VME | CPUID_HT,
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
- CPUID_EXT_POPCNT,
- .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
- CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
- CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
- CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP,
- /* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
- CPUID_EXT3_CR8LEG,
- CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
- CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
- .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
- CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
- .svm_features = CPUID_SVM_NPT | CPUID_SVM_LBRV,
- .xlevel = 0x8000001A,
- .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
- },
- {
- .name = "core2duo",
- .level = 10,
- .family = 6,
- .model = 15,
- .stepping = 11,
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- CPUID_PSE36 | CPUID_VME | CPUID_DTS | CPUID_ACPI | CPUID_SS |
- CPUID_HT | CPUID_TM | CPUID_PBE,
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
- CPUID_EXT_DTES64 | CPUID_EXT_DSCPL | CPUID_EXT_VMX | CPUID_EXT_EST |
- CPUID_EXT_TM2 | CPUID_EXT_CX16 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
- .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
- .ext3_features = CPUID_EXT3_LAHF_LM,
- .xlevel = 0x80000008,
- .model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz",
- },
- {
- .name = "kvm64",
- .level = 5,
- .vendor1 = CPUID_VENDOR_INTEL_1,
- .vendor2 = CPUID_VENDOR_INTEL_2,
- .vendor3 = CPUID_VENDOR_INTEL_3,
- .family = 15,
- .model = 6,
- .stepping = 1,
- /* Missing: CPUID_VME, CPUID_HT */
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- CPUID_PSE36,
- /* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
- /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
- .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) |
- CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
- /* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
- CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
- CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
- CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */
- .ext3_features = 0,
- .xlevel = 0x80000008,
- .model_id = "Common KVM processor"
- },
- {
- .name = "qemu32",
- .level = 4,
- .family = 6,
- .model = 3,
- .stepping = 3,
- .features = PPRO_FEATURES,
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
- .xlevel = 0x80000004,
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
- },
- {
- .name = "kvm32",
- .level = 5,
- .family = 15,
- .model = 6,
- .stepping = 1,
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36,
- .ext_features = CPUID_EXT_SSE3,
- .ext2_features = PPRO_FEATURES & EXT2_FEATURE_MASK,
- .ext3_features = 0,
- .xlevel = 0x80000008,
- .model_id = "Common 32-bit KVM processor"
- },
- {
- .name = "coreduo",
- .level = 10,
- .family = 6,
- .model = 14,
- .stepping = 8,
- .features = PPRO_FEATURES | CPUID_VME |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_DTS | CPUID_ACPI |
- CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_VMX |
- CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
- .ext2_features = CPUID_EXT2_NX,
- .xlevel = 0x80000008,
- .model_id = "Genuine Intel(R) CPU T2600 @ 2.16GHz",
- },
- {
- .name = "486",
- .level = 1,
- .family = 4,
- .model = 0,
- .stepping = 0,
- .features = I486_FEATURES,
- .xlevel = 0,
- },
- {
- .name = "pentium",
- .level = 1,
- .family = 5,
- .model = 4,
- .stepping = 3,
- .features = PENTIUM_FEATURES,
- .xlevel = 0,
- },
- {
- .name = "pentium2",
- .level = 2,
- .family = 6,
- .model = 5,
- .stepping = 2,
- .features = PENTIUM2_FEATURES,
- .xlevel = 0,
- },
- {
- .name = "pentium3",
- .level = 2,
- .family = 6,
- .model = 7,
- .stepping = 3,
- .features = PENTIUM3_FEATURES,
- .xlevel = 0,
- },
- {
- .name = "athlon",
- .level = 2,
- .vendor1 = CPUID_VENDOR_AMD_1,
- .vendor2 = CPUID_VENDOR_AMD_2,
- .vendor3 = CPUID_VENDOR_AMD_3,
- .family = 6,
- .model = 2,
- .stepping = 3,
- .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA,
- .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
- .xlevel = 0x80000008,
- /* XXX: put another string ? */
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
- },
- {
- .name = "n270",
- /* original is on level 10 */
- .level = 5,
- .family = 6,
- .model = 28,
- .stepping = 2,
- .features = PPRO_FEATURES |
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME | CPUID_DTS |
- CPUID_ACPI | CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
- /* Some CPUs got no CPUID_SEP */
- .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
- CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR,
- .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) | CPUID_EXT2_NX,
- .ext3_features = CPUID_EXT3_LAHF_LM,
- .xlevel = 0x8000000A,
- .model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz",
- },
-};
-
-static int cpu_x86_fill_model_id(char *str)
-{
- uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
- int i;
-
- for (i = 0; i < 3; i++) {
- host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
- memcpy(str + i * 16 + 0, &eax, 4);
- memcpy(str + i * 16 + 4, &ebx, 4);
- memcpy(str + i * 16 + 8, &ecx, 4);
- memcpy(str + i * 16 + 12, &edx, 4);
- }
- return 0;
-}
-
-static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
-{
- uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
-
- x86_cpu_def->name = "host";
- host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->level = eax;
- x86_cpu_def->vendor1 = ebx;
- x86_cpu_def->vendor2 = edx;
- x86_cpu_def->vendor3 = ecx;
-
- host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
- x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
- x86_cpu_def->stepping = eax & 0x0F;
- x86_cpu_def->ext_features = ecx;
- x86_cpu_def->features = edx;
-
- host_cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->xlevel = eax;
-
- host_cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->ext2_features = edx;
- x86_cpu_def->ext3_features = ecx;
- cpu_x86_fill_model_id(x86_cpu_def->model_id);
- x86_cpu_def->vendor_override = 0;
-
- /* Call Centaur's CPUID instruction. */
- if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
- x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
- x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
- host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
- if (eax >= 0xC0000001) {
- /* Support VIA max extended level */
- x86_cpu_def->xlevel2 = eax;
- host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->ext4_features = edx;
- }
- }
-
- /*
- * Every SVM feature requires emulation support in KVM - so we can't just
- * read the host features here. KVM might even support SVM features not
- * available on the host hardware. Just set all bits and mask out the
- * unsupported ones later.
- */
- x86_cpu_def->svm_features = -1;
-
- return 0;
-}
-
-static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
-{
- int i;
-
- for (i = 0; i < 32; ++i)
- if (1 << i & mask) {
- fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
- " flag '%s' [0x%08x]\n",
- f->cpuid >> 16, f->cpuid & 0xffff,
- f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
- break;
- }
- return 0;
-}
-
-/* best effort attempt to inform user requested cpu flags aren't making
- * their way to the guest. Note: ft[].check_feat ideally should be
- * specified via a guest_def field to suppress report of extraneous flags.
- */
-static int check_features_against_host(x86_def_t *guest_def)
-{
- x86_def_t host_def;
- uint32_t mask;
- int rv, i;
- struct model_features_t ft[] = {
- {&guest_def->features, &host_def.features,
- ~0, feature_name, 0x00000000},
- {&guest_def->ext_features, &host_def.ext_features,
- ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
- {&guest_def->ext2_features, &host_def.ext2_features,
- ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
- {&guest_def->ext3_features, &host_def.ext3_features,
- ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
-
- cpu_x86_fill_host(&host_def);
- for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i)
- for (mask = 1; mask; mask <<= 1)
- if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
- !(*ft[i].host_feat & mask)) {
- unavailable_host_feature(&ft[i], mask);
- rv = 1;
- }
- return rv;
-}
-
-static void x86_cpuid_version_set_family(CPUX86State *env, int family)
-{
- env->cpuid_version &= ~0xff00f00;
- if (family > 0x0f) {
- env->cpuid_version |= 0xf00 | ((family - 0x0f) << 20);
- } else {
- env->cpuid_version |= family << 8;
- }
-}
-
-static void x86_cpuid_version_set_model(CPUX86State *env, int model)
-{
- env->cpuid_version &= ~0xf00f0;
- env->cpuid_version |= ((model & 0xf) << 4) | ((model >> 4) << 16);
-}
-
-static void x86_cpuid_version_set_stepping(CPUX86State *env, int stepping)
-{
- env->cpuid_version &= ~0xf;
- env->cpuid_version |= stepping & 0xf;
-}
-
-static void x86_cpuid_set_model_id(CPUX86State *env, const char *model_id)
-{
- int c, len, i;
-
- if (model_id == NULL) {
- model_id = "";
- }
- len = strlen(model_id);
- for (i = 0; i < 48; i++) {
- if (i >= len) {
- c = '\0';
- } else {
- c = (uint8_t)model_id[i];
- }
- env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
- }
-}
-
-static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
-{
- unsigned int i;
- x86_def_t *def;
-
- char *s = g_strdup(cpu_model);
- char *featurestr, *name = strtok(s, ",");
- /* Features to be added*/
- uint32_t plus_features = 0, plus_ext_features = 0;
- uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
- uint32_t plus_kvm_features = 0, plus_svm_features = 0;
- /* Features to be removed */
- uint32_t minus_features = 0, minus_ext_features = 0;
- uint32_t minus_ext2_features = 0, minus_ext3_features = 0;
- uint32_t minus_kvm_features = 0, minus_svm_features = 0;
- uint32_t numvalue;
-
- for (def = x86_defs; def; def = def->next)
- if (name && !strcmp(name, def->name))
- break;
- if (kvm_enabled() && name && strcmp(name, "host") == 0) {
- cpu_x86_fill_host(x86_cpu_def);
- } else if (!def) {
- goto error;
- } else {
- memcpy(x86_cpu_def, def, sizeof(*def));
- }
-
- plus_kvm_features = ~0; /* not supported bits will be filtered out later */
-
- add_flagname_to_bitmaps("hypervisor", &plus_features,
- &plus_ext_features, &plus_ext2_features, &plus_ext3_features,
- &plus_kvm_features, &plus_svm_features);
-
- featurestr = strtok(NULL, ",");
-
- while (featurestr) {
- char *val;
- if (featurestr[0] == '+') {
- add_flagname_to_bitmaps(featurestr + 1, &plus_features,
- &plus_ext_features, &plus_ext2_features,
- &plus_ext3_features, &plus_kvm_features,
- &plus_svm_features);
- } else if (featurestr[0] == '-') {
- add_flagname_to_bitmaps(featurestr + 1, &minus_features,
- &minus_ext_features, &minus_ext2_features,
- &minus_ext3_features, &minus_kvm_features,
- &minus_svm_features);
- } else if ((val = strchr(featurestr, '='))) {
- *val = 0; val++;
- if (!strcmp(featurestr, "family")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->family = numvalue;
- } else if (!strcmp(featurestr, "model")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err || numvalue > 0xff) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->model = numvalue;
- } else if (!strcmp(featurestr, "stepping")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err || numvalue > 0xf) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->stepping = numvalue ;
- } else if (!strcmp(featurestr, "level")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->level = numvalue;
- } else if (!strcmp(featurestr, "xlevel")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- if (numvalue < 0x80000000) {
- numvalue += 0x80000000;
- }
- x86_cpu_def->xlevel = numvalue;
- } else if (!strcmp(featurestr, "vendor")) {
- if (strlen(val) != 12) {
- fprintf(stderr, "vendor string must be 12 chars long\n");
- goto error;
- }
- x86_cpu_def->vendor1 = 0;
- x86_cpu_def->vendor2 = 0;
- x86_cpu_def->vendor3 = 0;
- for(i = 0; i < 4; i++) {
- x86_cpu_def->vendor1 |= ((uint8_t)val[i ]) << (8 * i);
- x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i);
- x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i);
- }
- x86_cpu_def->vendor_override = 1;
- } else if (!strcmp(featurestr, "model_id")) {
- pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id),
- val);
- } else if (!strcmp(featurestr, "tsc_freq")) {
- int64_t tsc_freq;
- char *err;
-
- tsc_freq = strtosz_suffix_unit(val, &err,
- STRTOSZ_DEFSUFFIX_B, 1000);
- if (tsc_freq < 0 || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- x86_cpu_def->tsc_khz = tsc_freq / 1000;
- } else if (!strcmp(featurestr, "hv_spinlocks")) {
- char *err;
- numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- hyperv_set_spinlock_retries(numvalue);
- } else {
- fprintf(stderr, "unrecognized feature %s\n", featurestr);
- goto error;
- }
- } else if (!strcmp(featurestr, "check")) {
- check_cpuid = 1;
- } else if (!strcmp(featurestr, "enforce")) {
- check_cpuid = enforce_cpuid = 1;
- } else if (!strcmp(featurestr, "hv_relaxed")) {
- hyperv_enable_relaxed_timing(true);
- } else if (!strcmp(featurestr, "hv_vapic")) {
- hyperv_enable_vapic_recommended(true);
- } else {
- fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
- goto error;
- }
- featurestr = strtok(NULL, ",");
- }
- x86_cpu_def->features |= plus_features;
- x86_cpu_def->ext_features |= plus_ext_features;
- x86_cpu_def->ext2_features |= plus_ext2_features;
- x86_cpu_def->ext3_features |= plus_ext3_features;
- x86_cpu_def->kvm_features |= plus_kvm_features;
- x86_cpu_def->svm_features |= plus_svm_features;
- x86_cpu_def->features &= ~minus_features;
- x86_cpu_def->ext_features &= ~minus_ext_features;
- x86_cpu_def->ext2_features &= ~minus_ext2_features;
- x86_cpu_def->ext3_features &= ~minus_ext3_features;
- x86_cpu_def->kvm_features &= ~minus_kvm_features;
- x86_cpu_def->svm_features &= ~minus_svm_features;
- if (check_cpuid) {
- if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
- goto error;
- }
- g_free(s);
- return 0;
-
-error:
- g_free(s);
- return -1;
-}
-
-/* generate a composite string into buf of all cpuid names in featureset
- * selected by fbits. indicate truncation at bufsize in the event of overflow.
- * if flags, suppress names undefined in featureset.
- */
-static void listflags(char *buf, int bufsize, uint32_t fbits,
- const char **featureset, uint32_t flags)
-{
- const char **p = &featureset[31];
- char *q, *b, bit;
- int nc;
-
- b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
- *buf = '\0';
- for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
- if (fbits & 1 << bit && (*p || !flags)) {
- if (*p)
- nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
- else
- nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
- if (bufsize <= nc) {
- if (b) {
- memcpy(b, "...", sizeof("..."));
- }
- return;
- }
- q += nc;
- bufsize -= nc;
- }
-}
-
-/* generate CPU information:
- * -? list model names
- * -?model list model names/IDs
- * -?dump output all model (x86_def_t) data
- * -?cpuid list all recognized cpuid flag names
- */
-void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
-{
- unsigned char model = !strcmp("?model", optarg);
- unsigned char dump = !strcmp("?dump", optarg);
- unsigned char cpuid = !strcmp("?cpuid", optarg);
- x86_def_t *def;
- char buf[256];
-
- if (cpuid) {
- (*cpu_fprintf)(f, "Recognized CPUID flags:\n");
- listflags(buf, sizeof (buf), (uint32_t)~0, feature_name, 1);
- (*cpu_fprintf)(f, " f_edx: %s\n", buf);
- listflags(buf, sizeof (buf), (uint32_t)~0, ext_feature_name, 1);
- (*cpu_fprintf)(f, " f_ecx: %s\n", buf);
- listflags(buf, sizeof (buf), (uint32_t)~0, ext2_feature_name, 1);
- (*cpu_fprintf)(f, " extf_edx: %s\n", buf);
- listflags(buf, sizeof (buf), (uint32_t)~0, ext3_feature_name, 1);
- (*cpu_fprintf)(f, " extf_ecx: %s\n", buf);
- return;
- }
- for (def = x86_defs; def; def = def->next) {
- snprintf(buf, sizeof (buf), def->flags ? "[%s]": "%s", def->name);
- if (model || dump) {
- (*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
- } else {
- (*cpu_fprintf)(f, "x86 %16s\n", buf);
- }
- if (dump) {
- memcpy(buf, &def->vendor1, sizeof (def->vendor1));
- memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
- memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
- buf[12] = '\0';
- (*cpu_fprintf)(f,
- " family %d model %d stepping %d level %d xlevel 0x%x"
- " vendor \"%s\"\n",
- def->family, def->model, def->stepping, def->level,
- def->xlevel, buf);
- listflags(buf, sizeof (buf), def->features, feature_name, 0);
- (*cpu_fprintf)(f, " feature_edx %08x (%s)\n", def->features,
- buf);
- listflags(buf, sizeof (buf), def->ext_features, ext_feature_name,
- 0);
- (*cpu_fprintf)(f, " feature_ecx %08x (%s)\n", def->ext_features,
- buf);
- listflags(buf, sizeof (buf), def->ext2_features, ext2_feature_name,
- 0);
- (*cpu_fprintf)(f, " extfeature_edx %08x (%s)\n",
- def->ext2_features, buf);
- listflags(buf, sizeof (buf), def->ext3_features, ext3_feature_name,
- 0);
- (*cpu_fprintf)(f, " extfeature_ecx %08x (%s)\n",
- def->ext3_features, buf);
- (*cpu_fprintf)(f, "\n");
- }
- }
- if (kvm_enabled()) {
- (*cpu_fprintf)(f, "x86 %16s\n", "[host]");
- }
-}
-
-int cpu_x86_register (CPUX86State *env, const char *cpu_model)
-{
- x86_def_t def1, *def = &def1;
-
- memset(def, 0, sizeof(*def));
-
- if (cpu_x86_find_by_name(def, cpu_model) < 0)
- return -1;
- if (def->vendor1) {
- env->cpuid_vendor1 = def->vendor1;
- env->cpuid_vendor2 = def->vendor2;
- env->cpuid_vendor3 = def->vendor3;
- } else {
- env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1;
- env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2;
- env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3;
- }
- env->cpuid_vendor_override = def->vendor_override;
- env->cpuid_level = def->level;
- x86_cpuid_version_set_family(env, def->family);
- x86_cpuid_version_set_model(env, def->model);
- x86_cpuid_version_set_stepping(env, def->stepping);
- env->cpuid_features = def->features;
- env->cpuid_ext_features = def->ext_features;
- env->cpuid_ext2_features = def->ext2_features;
- env->cpuid_ext3_features = def->ext3_features;
- env->cpuid_xlevel = def->xlevel;
- env->cpuid_kvm_features = def->kvm_features;
- env->cpuid_svm_features = def->svm_features;
- env->cpuid_ext4_features = def->ext4_features;
- env->cpuid_xlevel2 = def->xlevel2;
- env->tsc_khz = def->tsc_khz;
- if (!kvm_enabled()) {
- env->cpuid_features &= TCG_FEATURES;
- env->cpuid_ext_features &= TCG_EXT_FEATURES;
- env->cpuid_ext2_features &= (TCG_EXT2_FEATURES
-#ifdef TARGET_X86_64
- | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM
-#endif
- );
- env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
- env->cpuid_svm_features &= TCG_SVM_FEATURES;
- }
- x86_cpuid_set_model_id(env, def->model_id);
- return 0;
-}
-
-#if !defined(CONFIG_USER_ONLY)
-/* copy vendor id string to 32 bit register, nul pad as needed
- */
-static void cpyid(const char *s, uint32_t *id)
-{
- char *d = (char *)id;
- char i;
-
- for (i = sizeof (*id); i--; )
- *d++ = *s ? *s++ : '\0';
-}
-
-/* interpret radix and convert from string to arbitrary scalar,
- * otherwise flag failure
- */
-#define setscalar(pval, str, perr) \
-{ \
- char *pend; \
- unsigned long ul; \
- \
- ul = strtoul(str, &pend, 0); \
- *str && !*pend ? (*pval = ul) : (*perr = 1); \
-}
-
-/* map cpuid options to feature bits, otherwise return failure
- * (option tags in *str are delimited by whitespace)
- */
-static void setfeatures(uint32_t *pval, const char *str,
- const char **featureset, int *perr)
-{
- const char *p, *q;
-
- for (q = p = str; *p || *q; q = p) {
- while (iswhite(*p))
- q = ++p;
- while (*p && !iswhite(*p))
- ++p;
- if (!*q && !*p)
- return;
- if (!lookup_feature(pval, q, p, featureset)) {
- fprintf(stderr, "error: feature \"%.*s\" not available in set\n",
- (int)(p - q), q);
- *perr = 1;
- return;
- }
- }
-}
-
-/* map config file options to x86_def_t form
- */
-static int cpudef_setfield(const char *name, const char *str, void *opaque)
-{
- x86_def_t *def = opaque;
- int err = 0;
-
- if (!strcmp(name, "name")) {
- g_free((void *)def->name);
- def->name = g_strdup(str);
- } else if (!strcmp(name, "model_id")) {
- strncpy(def->model_id, str, sizeof (def->model_id));
- } else if (!strcmp(name, "level")) {
- setscalar(&def->level, str, &err)
- } else if (!strcmp(name, "vendor")) {
- cpyid(&str[0], &def->vendor1);
- cpyid(&str[4], &def->vendor2);
- cpyid(&str[8], &def->vendor3);
- } else if (!strcmp(name, "family")) {
- setscalar(&def->family, str, &err)
- } else if (!strcmp(name, "model")) {
- setscalar(&def->model, str, &err)
- } else if (!strcmp(name, "stepping")) {
- setscalar(&def->stepping, str, &err)
- } else if (!strcmp(name, "feature_edx")) {
- setfeatures(&def->features, str, feature_name, &err);
- } else if (!strcmp(name, "feature_ecx")) {
- setfeatures(&def->ext_features, str, ext_feature_name, &err);
- } else if (!strcmp(name, "extfeature_edx")) {
- setfeatures(&def->ext2_features, str, ext2_feature_name, &err);
- } else if (!strcmp(name, "extfeature_ecx")) {
- setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
- } else if (!strcmp(name, "xlevel")) {
- setscalar(&def->xlevel, str, &err)
- } else {
- fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
- return (1);
- }
- if (err) {
- fprintf(stderr, "error: bad option value [%s = %s]\n", name, str);
- return (1);
- }
- return (0);
-}
-
-/* register config file entry as x86_def_t
- */
-static int cpudef_register(QemuOpts *opts, void *opaque)
-{
- x86_def_t *def = g_malloc0(sizeof (x86_def_t));
-
- qemu_opt_foreach(opts, cpudef_setfield, def, 1);
- def->next = x86_defs;
- x86_defs = def;
- return (0);
-}
-
-void cpu_clear_apic_feature(CPUX86State *env)
-{
- env->cpuid_features &= ~CPUID_APIC;
-}
-
-#endif /* !CONFIG_USER_ONLY */
-
-/* register "cpudef" models defined in configuration file. Here we first
- * preload any built-in definitions
- */
-void x86_cpudef_setup(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
- builtin_x86_defs[i].next = x86_defs;
- builtin_x86_defs[i].flags = 1;
- x86_defs = &builtin_x86_defs[i];
- }
-#if !defined(CONFIG_USER_ONLY)
- qemu_opts_foreach(qemu_find_opts("cpudef"), cpudef_register, NULL, 0);
-#endif
-}
-
-static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
- uint32_t *ecx, uint32_t *edx)
-{
- *ebx = env->cpuid_vendor1;
- *edx = env->cpuid_vendor2;
- *ecx = env->cpuid_vendor3;
-
- /* sysenter isn't supported on compatibility mode on AMD, syscall
- * isn't supported in compatibility mode on Intel.
- * Normally we advertise the actual cpu vendor, but you can override
- * this if you want to use KVM's sysenter/syscall emulation
- * in compatibility mode and when doing cross vendor migration
- */
- if (kvm_enabled() && ! env->cpuid_vendor_override) {
- host_cpuid(0, 0, NULL, ebx, ecx, edx);
- }
-}
-
-void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
- uint32_t *eax, uint32_t *ebx,
- uint32_t *ecx, uint32_t *edx)
-{
- /* test if maximum index reached */
- if (index & 0x80000000) {
- if (index > env->cpuid_xlevel) {
- if (env->cpuid_xlevel2 > 0) {
- /* Handle the Centaur's CPUID instruction. */
- if (index > env->cpuid_xlevel2) {
- index = env->cpuid_xlevel2;
- } else if (index < 0xC0000000) {
- index = env->cpuid_xlevel;
- }
- } else {
- index = env->cpuid_xlevel;
- }
- }
- } else {
- if (index > env->cpuid_level)
- index = env->cpuid_level;
- }
-
- switch(index) {
- case 0:
- *eax = env->cpuid_level;
- get_cpuid_vendor(env, ebx, ecx, edx);
- break;
- case 1:
- *eax = env->cpuid_version;
- *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
- *ecx = env->cpuid_ext_features;
- *edx = env->cpuid_features;
- if (env->nr_cores * env->nr_threads > 1) {
- *ebx |= (env->nr_cores * env->nr_threads) << 16;
- *edx |= 1 << 28; /* HTT bit */
- }
- break;
- case 2:
- /* cache info: needed for Pentium Pro compatibility */
- *eax = 1;
- *ebx = 0;
- *ecx = 0;
- *edx = 0x2c307d;
- break;
- case 4:
- /* cache info: needed for Core compatibility */
- if (env->nr_cores > 1) {
- *eax = (env->nr_cores - 1) << 26;
- } else {
- *eax = 0;
- }
- switch (count) {
- case 0: /* L1 dcache info */
- *eax |= 0x0000121;
- *ebx = 0x1c0003f;
- *ecx = 0x000003f;
- *edx = 0x0000001;
- break;
- case 1: /* L1 icache info */
- *eax |= 0x0000122;
- *ebx = 0x1c0003f;
- *ecx = 0x000003f;
- *edx = 0x0000001;
- break;
- case 2: /* L2 cache info */
- *eax |= 0x0000143;
- if (env->nr_threads > 1) {
- *eax |= (env->nr_threads - 1) << 14;
- }
- *ebx = 0x3c0003f;
- *ecx = 0x0000fff;
- *edx = 0x0000001;
- break;
- default: /* end of info */
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- }
- break;
- case 5:
- /* mwait info: needed for Core compatibility */
- *eax = 0; /* Smallest monitor-line size in bytes */
- *ebx = 0; /* Largest monitor-line size in bytes */
- *ecx = CPUID_MWAIT_EMX | CPUID_MWAIT_IBE;
- *edx = 0;
- break;
- case 6:
- /* Thermal and Power Leaf */
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- case 7:
- if (kvm_enabled()) {
- KVMState *s = env->kvm_state;
-
- *eax = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EAX);
- *ebx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EBX);
- *ecx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_ECX);
- *edx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EDX);
- } else {
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- }
- break;
- case 9:
- /* Direct Cache Access Information Leaf */
- *eax = 0; /* Bits 0-31 in DCA_CAP MSR */
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- case 0xA:
- /* Architectural Performance Monitoring Leaf */
- if (kvm_enabled()) {
- KVMState *s = env->kvm_state;
-
- *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX);
- *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX);
- *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX);
- *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX);
- } else {
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- }
- break;
- case 0xD:
- /* Processor Extended State */
- if (!(env->cpuid_ext_features & CPUID_EXT_XSAVE)) {
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- }
- if (kvm_enabled()) {
- KVMState *s = env->kvm_state;
-
- *eax = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EAX);
- *ebx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EBX);
- *ecx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_ECX);
- *edx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EDX);
- } else {
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- }
- break;
- case 0x80000000:
- *eax = env->cpuid_xlevel;
- *ebx = env->cpuid_vendor1;
- *edx = env->cpuid_vendor2;
- *ecx = env->cpuid_vendor3;
- break;
- case 0x80000001:
- *eax = env->cpuid_version;
- *ebx = 0;
- *ecx = env->cpuid_ext3_features;
- *edx = env->cpuid_ext2_features;
-
- /* The Linux kernel checks for the CMPLegacy bit and
- * discards multiple thread information if it is set.
- * So dont set it here for Intel to make Linux guests happy.
- */
- if (env->nr_cores * env->nr_threads > 1) {
- uint32_t tebx, tecx, tedx;
- get_cpuid_vendor(env, &tebx, &tecx, &tedx);
- if (tebx != CPUID_VENDOR_INTEL_1 ||
- tedx != CPUID_VENDOR_INTEL_2 ||
- tecx != CPUID_VENDOR_INTEL_3) {
- *ecx |= 1 << 1; /* CmpLegacy bit */
- }
- }
- break;
- case 0x80000002:
- case 0x80000003:
- case 0x80000004:
- *eax = env->cpuid_model[(index - 0x80000002) * 4 + 0];
- *ebx = env->cpuid_model[(index - 0x80000002) * 4 + 1];
- *ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2];
- *edx = env->cpuid_model[(index - 0x80000002) * 4 + 3];
- break;
- case 0x80000005:
- /* cache info (L1 cache) */
- *eax = 0x01ff01ff;
- *ebx = 0x01ff01ff;
- *ecx = 0x40020140;
- *edx = 0x40020140;
- break;
- case 0x80000006:
- /* cache info (L2 cache) */
- *eax = 0;
- *ebx = 0x42004200;
- *ecx = 0x02008140;
- *edx = 0;
- break;
- case 0x80000008:
- /* virtual & phys address size in low 2 bytes. */
-/* XXX: This value must match the one used in the MMU code. */
- if (env->cpuid_ext2_features & CPUID_EXT2_LM) {
- /* 64 bit processor */
-/* XXX: The physical address space is limited to 42 bits in exec.c. */
- *eax = 0x00003028; /* 48 bits virtual, 40 bits physical */
- } else {
- if (env->cpuid_features & CPUID_PSE36)
- *eax = 0x00000024; /* 36 bits physical */
- else
- *eax = 0x00000020; /* 32 bits physical */
- }
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- if (env->nr_cores * env->nr_threads > 1) {
- *ecx |= (env->nr_cores * env->nr_threads) - 1;
- }
- break;
- case 0x8000000A:
- if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
- *eax = 0x00000001; /* SVM Revision */
- *ebx = 0x00000010; /* nr of ASIDs */
- *ecx = 0;
- *edx = env->cpuid_svm_features; /* optional features */
- } else {
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- }
- break;
- case 0xC0000000:
- *eax = env->cpuid_xlevel2;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- case 0xC0000001:
- /* Support for VIA CPU's CPUID instruction */
- *eax = env->cpuid_version;
- *ebx = 0;
- *ecx = 0;
- *edx = env->cpuid_ext4_features;
- break;
- case 0xC0000002:
- case 0xC0000003:
- case 0xC0000004:
- /* Reserved for the future, and now filled with zero */
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- default:
- /* reserved values: zero */
- *eax = 0;
- *ebx = 0;
- *ecx = 0;
- *edx = 0;
- break;
- }
-}
commit 4e1957acc854b2f3f3068c75cef2a429f9b97011
Merge: 6da25bd... ff71f2e...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Apr 10 08:21:58 2012 -0500
Merge commit 'ff71f2e8cacefae99179993204172bc65e4303df' into staging
* commit 'ff71f2e8cacefae99179993204172bc65e4303df': (21 commits)
rtl8139: do the network/host communication only in normal operating mode
rtl8139: correctly check the opmode
net: move compute_mcast_idx() to net.h
rtl8139: support byte read to TxStatus registers
rtl8139: remove unused marco
rtl8139: limit transmission buffer size in c+ mode
pci_regs: Add PCI_EXP_TYPE_PCIE_BRIDGE
virtio-net: add DATA_VALID flag
pci_bridge: upper 32 bit are long registers
pci: fix bridge IO/BASE
pcie: drop functionality moved to core
pci: set memory type for memory behind the bridge
pci: add standard bridge device
slotid: add slot id capability
shpc: standard hot plug controller
pci_bridge: user-friendly default bus name
pci: make another unused extern function static
pci: don't export an internal function
pci_regs: Fix value of PCI_EXP_TYPE_RC_EC.
pci: Do not check if a bus exist in pci_parse_devaddr.
...
commit 6da25bd5e8355230b9562417e386728c31783002
Merge: bb5d8dd... a15fef2...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Apr 10 08:17:36 2012 -0500
Merge remote-tracking branch 'qmp/queue/qmp' into staging
* qmp/queue/qmp:
qapi: convert device_del
qdev: qdev_unplug(): use error_set()
commit bb5d8dd757eaa8f9a048c5205c69bed20ea373d1
Merge: 72fe3aa... 50d30c2...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Apr 10 08:16:12 2012 -0500
Merge remote-tracking branch 'kwolf/for-anthony' into staging
* kwolf/for-anthony: (46 commits)
qed: remove incoming live migration blocker
qed: honor BDRV_O_INCOMING for incoming live migration
migration: clear BDRV_O_INCOMING flags on end of incoming live migration
qed: add bdrv_invalidate_cache to be called after incoming live migration
blockdev: open images with BDRV_O_INCOMING on incoming live migration
block: add a function to clear incoming live migration flags
block: Add new BDRV_O_INCOMING flag to notice incoming live migration
block stream: close unused files and update ->backing_hd
qemu-iotests: Fix call syntax for qemu-io
qemu-iotests: Fix call syntax for qemu-img
qemu-iotests: Test unknown qcow2 header extensions
qemu-iotests: qcow2.py
sheepdog: fix send req helpers
sheepdog: implement SD_OP_FLUSH_VDI operation
block: bdrv_append() fixes
qed: track dirty flag status
qemu-img: add dirty flag status
qed: image fragmentation statistics
qemu-img: add image fragmentation statistics
block: document job API
...
commit 72fe3aaed94936739abfa158fa28f147b75ae9ff
Merge: 2c097f6... 53fbf7b...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue Apr 10 08:10:41 2012 -0500
Merge remote-tracking branch 'stefanha/trivial-patches' into staging
* stefanha/trivial-patches:
make: fix clean rule by removing build file in qom/
configure: Link qga against UST tracing related libraries
configure: Link QEMU against 'liburcu-bp'
main-loop: make qemu_event_handle static
block/curl: Replace usleep by g_usleep
qtest: Add missing GCC_FMT_ATTR
w32: Undefine error constants before their redefinition
configure: fix mingw32 libs_qga typo
commit 2c097f6003f2a11416706ae3252c2860ed2257a9
Author: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
Date: Tue Apr 10 14:05:52 2012 +1000
petalogix_s3adsp1800: deleted bad FIXME comment
This FIXME has already been actioned. Deleted comment.
Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index ff154c7..8b37336 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -51,7 +51,6 @@
static void machine_cpu_reset(CPUMBState *env)
{
- /* FIXME: move to machine specfic cpu reset */
env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family. */
}
commit a15fef21c746e3aa0a94cf7b5bd9799886236666
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date: Thu Mar 29 12:38:50 2012 -0300
qapi: convert device_del
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hmp-commands.hx b/hmp-commands.hx
index bd35a3e..a6f5a84 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -622,8 +622,7 @@ ETEXI
.args_type = "id:s",
.params = "device",
.help = "remove device",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_device_del,
+ .mhandler.cmd = hmp_device_del,
},
STEXI
diff --git a/hmp.c b/hmp.c
index 9cf2d13..f3e5163 100644
--- a/hmp.c
+++ b/hmp.c
@@ -934,3 +934,12 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
qemu_mod_timer(status->timer, qemu_get_clock_ms(rt_clock));
}
}
+
+void hmp_device_del(Monitor *mon, const QDict *qdict)
+{
+ const char *id = qdict_get_str(qdict, "id");
+ Error *err = NULL;
+
+ qmp_device_del(id, &err);
+ hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 8807853..443b812 100644
--- a/hmp.h
+++ b/hmp.h
@@ -60,5 +60,6 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict);
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate(Monitor *mon, const QDict *qdict);
+void hmp_device_del(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index fd56afe..81d6548 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -19,6 +19,7 @@
#include "qdev.h"
#include "monitor.h"
+#include "qmp-commands.h"
/*
* Aliases were a bad idea from the start. Let's keep them
@@ -570,26 +571,17 @@ int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
return 0;
}
-int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_device_del(const char *id, Error **errp)
{
- const char *id = qdict_get_str(qdict, "id");
- Error *local_err = NULL;
DeviceState *dev;
dev = qdev_find_recursive(sysbus_get_default(), id);
if (NULL == dev) {
- qerror_report(QERR_DEVICE_NOT_FOUND, id);
- return -1;
- }
-
- qdev_unplug(dev, &local_err);
- if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, id);
+ return;
}
- return 0;
+ qdev_unplug(dev, errp);
}
void qdev_machine_init(void)
diff --git a/qapi-schema.json b/qapi-schema.json
index 0d11d6e..ace55f3 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1701,3 +1701,23 @@
# Since: 1.1
##
{ 'command': 'xen-save-devices-state', 'data': {'filename': 'str'} }
+
+##
+# @device_del:
+#
+# Remove a device from a guest
+#
+# @id: the name of the device
+#
+# Returns: Nothing on success
+# If @id is not a valid device, DeviceNotFound
+# If the device does not support unplug, BusNoHotplug
+#
+# Notes: When this command completes, the device may not be removed from the
+# guest. Hot removal is an operation that requires guest cooperation.
+# This command merely requests that the guest begin the hot removal
+# process.
+#
+# Since: 0.14.0
+##
+{ 'command': 'device_del', 'data': {'id': 'str'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 9447871..c09ee85 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -314,10 +314,7 @@ EQMP
{
.name = "device_del",
.args_type = "id:s",
- .params = "device",
- .help = "remove device",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_device_del,
+ .mhandler.cmd_new = qmp_marshal_input_device_del,
},
SQMP
commit 56f9107e439c32aa00d58d117a9b664551328f1e
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date: Wed Mar 14 17:37:38 2012 -0300
qdev: qdev_unplug(): use error_set()
It currently uses qerror_report(), but next commit will convert
the drive_del command to the QAPI and this requires using
error_set().
One particularity of qerror_report() is that it knows when it's
running on monitor context or command-line context and prints the
error message accordingly. error_set() doesn't do this, so we
have to be careful not to drop error messages.
qdev_unplug() has three kinds of usages:
1. It's called when hot adding a device fails, to undo anything
that has been done before hitting the error
2. It's called by function monitor functions like device_del(),
to unplug a device
3. It's used by xen_platform.c in a way that doesn't _seem_ to
be in monitor context
Only item 2 can print an error message to the user, this commit
maintains that.
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 5c6307f..c55d8b9 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -32,6 +32,7 @@
#include "virtio-blk.h"
#include "qemu-config.h"
#include "blockdev.h"
+#include "error.h"
#if defined(TARGET_I386)
static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
@@ -191,7 +192,7 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
dev = NULL;
if (dev && dinfo) {
if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) {
- qdev_unplug(&dev->qdev);
+ qdev_unplug(&dev->qdev, NULL);
dev = NULL;
}
}
@@ -258,6 +259,7 @@ static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
PCIDevice *d;
int dom, bus;
unsigned slot;
+ Error *local_err = NULL;
if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
return -1;
@@ -268,7 +270,15 @@ static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
monitor_printf(mon, "slot %d empty\n", slot);
return -1;
}
- return qdev_unplug(&d->qdev);
+
+ qdev_unplug(&d->qdev, &local_err);
+ if (error_is_set(&local_err)) {
+ monitor_printf(mon, "%s\n", error_get_pretty(local_err));
+ error_free(local_err);
+ return -1;
+ }
+
+ return 0;
}
void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict)
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 4783366..fd56afe 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -573,6 +573,7 @@ int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *id = qdict_get_str(qdict, "id");
+ Error *local_err = NULL;
DeviceState *dev;
dev = qdev_find_recursive(sysbus_get_default(), id);
@@ -580,7 +581,15 @@ int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
qerror_report(QERR_DEVICE_NOT_FOUND, id);
return -1;
}
- return qdev_unplug(dev);
+
+ qdev_unplug(dev, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
+ }
+
+ return 0;
}
void qdev_machine_init(void)
diff --git a/hw/qdev.c b/hw/qdev.c
index 0d3c0fc..afbc975 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -28,6 +28,7 @@
#include "net.h"
#include "qdev.h"
#include "sysemu.h"
+#include "error.h"
int qdev_hotplug = 0;
static bool qdev_hot_added = false;
@@ -182,19 +183,22 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
dev->alias_required_for_version = required_for_version;
}
-int qdev_unplug(DeviceState *dev)
+void qdev_unplug(DeviceState *dev, Error **errp)
{
DeviceClass *dc = DEVICE_GET_CLASS(dev);
if (!dev->parent_bus->allow_hotplug) {
- qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
- return -1;
+ error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
+ return;
}
assert(dc->unplug != NULL);
qdev_hot_removed = true;
- return dc->unplug(dev);
+ if (dc->unplug(dev) < 0) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
+ }
}
static int qdev_reset_one(DeviceState *dev, void *opaque)
diff --git a/hw/qdev.h b/hw/qdev.h
index a8df42f..7cafa8c 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -7,6 +7,7 @@
#include "qemu-option.h"
#include "qapi/qapi-visit-core.h"
#include "qemu/object.h"
+#include "error.h"
typedef struct Property Property;
@@ -148,7 +149,7 @@ int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
void qdev_init_nofail(DeviceState *dev);
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version);
-int qdev_unplug(DeviceState *dev);
+void qdev_unplug(DeviceState *dev, Error **errp);
void qdev_free(DeviceState *dev);
int qdev_simple_unplug_cb(DeviceState *dev);
void qdev_machine_creation_done(void);
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index bdbe7bd..d865a5e 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -499,7 +499,7 @@ static void usb_msd_password_cb(void *opaque, int err)
err = usb_device_attach(&s->dev);
if (err)
- qdev_unplug(&s->dev.qdev);
+ qdev_unplug(&s->dev.qdev, NULL);
}
static const struct SCSIBusInfo usb_msd_scsi_info = {
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index 5a7c4cc..a9c52a6 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -87,7 +87,7 @@ static void unplug_nic(PCIBus *b, PCIDevice *d)
{
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
PCI_CLASS_NETWORK_ETHERNET) {
- qdev_unplug(&(d->qdev));
+ qdev_unplug(&(d->qdev), NULL);
}
}
@@ -100,7 +100,7 @@ static void unplug_disks(PCIBus *b, PCIDevice *d)
{
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
PCI_CLASS_STORAGE_IDE) {
- qdev_unplug(&(d->qdev));
+ qdev_unplug(&(d->qdev), NULL);
}
}
commit 7914cb3c738a03a5d5f7cb32c3768bc62eb1e944
Merge: 4266717... 221b3a3...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sun Apr 8 18:00:42 2012 +0000
Merge branch 'memory/core' of git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm
* 'memory/core' of git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm:
memory: check address space when a listener is registered
memory: print aliased IO ranges in info mtree
ioport: use INT64_MAX for IO ranges
commit 4266717d690987993d52f5e4745064f4dbb29824
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Apr 7 17:58:34 2012 +0200
Add QEMU_NORETURN to function cpu_io_recompile
cpu_io_recompile terminates by calling either cpu_abort or
cpu_resume_from_signal which both never return.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/exec-all.h b/exec-all.h
index 4758d88..fa7bdfe 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -87,7 +87,7 @@ int cpu_gen_code(CPUArchState *env, struct TranslationBlock *tb,
int cpu_restore_state(struct TranslationBlock *tb,
CPUArchState *env, uintptr_t searched_pc);
void QEMU_NORETURN cpu_resume_from_signal(CPUArchState *env1, void *puc);
-void cpu_io_recompile(CPUArchState *env, void *retaddr);
+void QEMU_NORETURN cpu_io_recompile(CPUArchState *env, void *retaddr);
TranslationBlock *tb_gen_code(CPUArchState *env,
target_ulong pc, target_ulong cs_base, int flags,
int cflags);
commit 38c30fb7a534da82371311ca7a56f2141008b2a5
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Apr 7 17:58:33 2012 +0200
Add QEMU_NORETURN to function cpu_resume_from_signal
cpu_resume_from_signal terminates by calling longjmp.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/exec-all.h b/exec-all.h
index a6d6519..4758d88 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -86,7 +86,7 @@ int cpu_gen_code(CPUArchState *env, struct TranslationBlock *tb,
int *gen_code_size_ptr);
int cpu_restore_state(struct TranslationBlock *tb,
CPUArchState *env, uintptr_t searched_pc);
-void cpu_resume_from_signal(CPUArchState *env1, void *puc);
+void QEMU_NORETURN cpu_resume_from_signal(CPUArchState *env1, void *puc);
void cpu_io_recompile(CPUArchState *env, void *retaddr);
TranslationBlock *tb_gen_code(CPUArchState *env,
target_ulong pc, target_ulong cs_base, int flags,
commit 5cbdb3a34bce4ee64dd203cfd74979409fa3d51e
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Apr 7 09:23:39 2012 +0200
Replace Qemu by QEMU in comments
The official spelling is QEMU.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Reviewed-by: Andreas Färber <afaerber at suse.de>
[blauwirbel at gmail.com: fixed comment style in hw/sun4m.c]
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 64e1cd9..b80aa8f 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -565,7 +565,7 @@ static void ivshmem_setup_msi(IVShmemState * s) {
msix_vector_use(&s->dev, i);
}
- /* allocate Qemu char devices for receiving interrupts */
+ /* allocate QEMU char devices for receiving interrupts */
s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
}
diff --git a/hw/pc.c b/hw/pc.c
index 83a1b5b..67f0479 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -776,7 +776,7 @@ static void load_linux(void *fw_cfg,
}
/* loader type */
- /* High nybble = B reserved for Qemu; low nybble is revision number.
+ /* High nybble = B reserved for QEMU; low nybble is revision number.
If this code is substantially changed, you may want to consider
incrementing the revision. */
if (protocol >= 0x200)
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 220c81d..f0a3ae4 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -1,5 +1,5 @@
/*
- * Qemu PowerPC 440 Bamboo board emulation
+ * QEMU PowerPC 440 Bamboo board emulation
*
* Copyright 2007 IBM Corporation.
* Authors:
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 5ee8cb3..f1dfbe1 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -1,5 +1,5 @@
/*
- * Qemu PowerPC MPC8544DS board emualtion
+ * QEMU PowerPC MPC8544DS board emulation
*
* Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
*
diff --git a/hw/ps2.c b/hw/ps2.c
index b1a67bc..f93cd24 100644
--- a/hw/ps2.c
+++ b/hw/ps2.c
@@ -88,7 +88,7 @@ typedef struct {
typedef struct {
PS2State common;
int scan_enabled;
- /* Qemu uses translated PC scancodes internally. To avoid multiple
+ /* QEMU uses translated PC scancodes internally. To avoid multiple
conversions we do the translation (if any) in the PS/2 emulation
not the keyboard controller. */
int translate;
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 7bcbf37..34088ad 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -932,8 +932,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14],
display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
- // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
- // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
+ /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
+ Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15],
serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
@@ -1581,8 +1581,8 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[12],
display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
- // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
- // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
+ /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
+ Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
escc_init(hwdef->serial_base, sbi_irq[12], sbi_irq[12],
serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
@@ -1762,8 +1762,8 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[1],
display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
- // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
- // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
+ /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
+ Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
escc_init(hwdef->serial_base, slavio_irq[1],
slavio_irq[1], serial_hds[0], serial_hds[1],
ESCC_CLOCK, 1);
diff --git a/ppc-dis.c b/ppc-dis.c
index ffdbec1..bc98cbe 100644
--- a/ppc-dis.c
+++ b/ppc-dis.c
@@ -5152,7 +5152,7 @@ powerpc_dialect (struct disassemble_info *info)
return dialect;
}
-/* Qemu default */
+/* QEMU default */
int
print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info)
{
diff --git a/qemu-queue.h b/qemu-queue.h
index 74d7122..9288cd8 100644
--- a/qemu-queue.h
+++ b/qemu-queue.h
@@ -1,7 +1,7 @@
/* $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */
/*
- * Qemu version: Copy from netbsd, removed debug code, removed some of
+ * QEMU version: Copy from netbsd, removed debug code, removed some of
* the implementations. Left in singly-linked lists, lists, simple
* queues, and tail queues.
*/
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 6c5d28b..74bf7f7 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -276,7 +276,7 @@ struct CPUAlphaState {
target_ulong t0, t1;
#endif
- /* Those resources are used only in Qemu core */
+ /* Those resources are used only in QEMU core */
CPU_COMMON
int error_code;
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 7430aa5..257c4c4 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -418,7 +418,7 @@ struct CPUMIPSState {
/* We waste some space so we can handle shadow registers like TCs. */
TCState tcs[MIPS_SHADOW_SET_MAX];
CPUMIPSFPUContext fpus[MIPS_FPU_MAX];
- /* Qemu */
+ /* QEMU */
int error_code;
uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index ca6f1cb..e7fb364 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -233,10 +233,10 @@ enum {
POWERPC_EXCP_DTLBE = 93, /* Data TLB error */
/* EOL */
POWERPC_EXCP_NB = 96,
- /* Qemu exceptions: used internally during code translation */
+ /* QEMU exceptions: used internally during code translation */
POWERPC_EXCP_STOP = 0x200, /* stop translation */
POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */
- /* Qemu exceptions: special cases we want to stop translation */
+ /* QEMU exceptions: special cases we want to stop translation */
POWERPC_EXCP_SYNC = 0x202, /* context synchronizing instruction */
POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only */
POWERPC_EXCP_STCX = 0x204 /* Conditional stores in user mode */
@@ -1041,7 +1041,7 @@ struct CPUPPCState {
/* opcode handlers */
opc_handler_t *opcodes[0x40];
- /* Those resources are used only in Qemu core */
+ /* Those resources are used only in QEMU core */
target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */
target_ulong hflags_nmsr; /* specific hflags, not coming from MSR */
int mmu_idx; /* precomputed MMU index to speed up mem accesses */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 39dcc27..e13b749 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -365,7 +365,7 @@ void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code,
tlb = &env->tlb.tlb6[nr];
LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
" PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
- /* Invalidate any pending reference in Qemu for this virtual address */
+ /* Invalidate any pending reference in QEMU for this virtual address */
__ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
tlb->pte0 = pte0;
tlb->pte1 = pte1;
@@ -729,7 +729,7 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
slb->esid &= ~SLB_ESID_V;
/* XXX: given the fact that segment size is 256 MB or 1TB,
* and we still don't have a tlb_flush_mask(env, n, mask)
- * in Qemu, we just invalidate all TLBs
+ * in QEMU, we just invalidate all TLBs
*/
do_invalidate = 1;
}
@@ -752,7 +752,7 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
/* XXX: given the fact that segment size is 256 MB or 1TB,
* and we still don't have a tlb_flush_mask(env, n, mask)
- * in Qemu, we just invalidate all TLBs
+ * in QEMU, we just invalidate all TLBs
*/
tlb_flush(env, 1);
}
@@ -2319,7 +2319,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
case POWERPC_MMU_2_06:
/* tlbie invalidate TLBs for all segments */
/* XXX: given the fact that there are too many segments to invalidate,
- * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
+ * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
* we just invalidate all TLBs
*/
tlb_flush(env, 1);
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 724f4c7..d929213 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -470,7 +470,7 @@ void kvm_arch_pre_run(CPUPPCState *env, struct kvm_run *run)
int r;
unsigned irq;
- /* PowerPC Qemu tracks the various core input pins (interrupt, critical
+ /* PowerPC QEMU tracks the various core input pins (interrupt, critical
* interrupt, reset, etc) in PPC-specific env->irq_input_state. */
if (!cap_interrupt_level &&
run->ready_for_interrupt_injection &&
diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
index 24fc6bc..a2e49cd 100644
--- a/target-ppc/kvm_ppc.c
+++ b/target-ppc/kvm_ppc.c
@@ -31,7 +31,7 @@ void kvmppc_init(void)
{
/* XXX The only reason KVM yields control back to qemu is device IO. Since
* an idle guest does no IO, qemu's device model will never get a chance to
- * run. So, until Qemu gains IO threads, we create this timer to ensure
+ * run. So, until QEMU gains IO threads, we create this timer to ensure
* that the device model gets a chance to run. */
kvmppc_timer_rate = get_ticks_per_sec() / 10;
kvmppc_timer = qemu_new_timer_ns(vm_clock, &kvmppc_timer_hack, NULL);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 367eefa..b1f8785 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -1796,17 +1796,17 @@ static void gen_spr_440 (CPUPPCState *env)
static void gen_spr_40x (CPUPPCState *env)
{
/* Cache */
- /* not emulated, as Qemu do not emulate caches */
+ /* not emulated, as QEMU do not emulate caches */
spr_register(env, SPR_40x_DCCR, "DCCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
- /* not emulated, as Qemu do not emulate caches */
+ /* not emulated, as QEMU do not emulate caches */
spr_register(env, SPR_40x_ICCR, "ICCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
- /* not emulated, as Qemu do not emulate caches */
+ /* not emulated, as QEMU do not emulate caches */
spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
@@ -1974,7 +1974,7 @@ static void gen_spr_401_403 (CPUPPCState *env)
SPR_NOACCESS, &spr_write_tbu,
0x00000000);
/* Debug */
- /* not emulated, as Qemu do not emulate caches */
+ /* not emulated, as QEMU do not emulate caches */
spr_register(env, SPR_403_CDBCR, "CDBCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -2012,12 +2012,12 @@ static void gen_spr_401 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_40x_sler,
0x00000000);
- /* not emulated, as Qemu never does speculative access */
+ /* not emulated, as QEMU never does speculative access */
spr_register(env, SPR_40x_SGR, "SGR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0xFFFFFFFF);
- /* not emulated, as Qemu do not emulate caches */
+ /* not emulated, as QEMU do not emulate caches */
spr_register(env, SPR_40x_DCWR, "DCWR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -3436,12 +3436,12 @@ static void init_proc_403GCX (CPUPPCState *env)
gen_spr_403_real(env);
gen_spr_403_mmu(env);
/* Bus access control */
- /* not emulated, as Qemu never does speculative access */
+ /* not emulated, as QEMU never does speculative access */
spr_register(env, SPR_40x_SGR, "SGR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0xFFFFFFFF);
- /* not emulated, as Qemu do not emulate caches */
+ /* not emulated, as QEMU do not emulate caches */
spr_register(env, SPR_40x_DCWR, "DCWR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -3488,12 +3488,12 @@ static void init_proc_405 (CPUPPCState *env)
gen_spr_40x(env);
gen_spr_405(env);
/* Bus access control */
- /* not emulated, as Qemu never does speculative access */
+ /* not emulated, as QEMU never does speculative access */
spr_register(env, SPR_40x_SGR, "SGR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0xFFFFFFFF);
- /* not emulated, as Qemu do not emulate caches */
+ /* not emulated, as QEMU do not emulate caches */
spr_register(env, SPR_40x_DCWR, "DCWR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -9442,13 +9442,13 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def)
}
if (env->irq_inputs == NULL) {
fprintf(stderr, "WARNING: no internal IRQ controller registered.\n"
- " Attempt Qemu to crash very soon !\n");
+ " Attempt QEMU to crash very soon !\n");
}
#endif
if (env->check_pow == NULL) {
fprintf(stderr, "WARNING: no power management check handler "
"registered.\n"
- " Attempt Qemu to crash very soon !\n");
+ " Attempt QEMU to crash very soon !\n");
}
}
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 0711205..e7d6e89 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -772,7 +772,7 @@ QemuCocoaView *cocoaView;
modalForWindow:normalWindow modalDelegate:self
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
} else {
- // or Launch Qemu, with the global args
+ // or launch QEMU, with the global args
[self startEmulationWithArgc:gArgc argv:(char **)gArgv];
}
}
diff --git a/ui/spice-display.c b/ui/spice-display.c
index cb8a7ad..5418eb3 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -219,7 +219,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
/*
* Called from spice server thread context (via interface_release_ressource)
* We do *not* hold the global qemu mutex here, so extra care is needed
- * when calling qemu functions. Qemu interfaces used:
+ * when calling qemu functions. QEMU interfaces used:
* - g_free (underlying glibc free is re-entrant).
*/
void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
commit c5ec15ea3b9374e6d493f8de7dfc170cec058068
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Apr 7 09:23:38 2012 +0200
Replace Qemu by QEMU in w32 installation path (prefix)
The official spelling is QEMU.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/configure b/configure
index 6f850a6..671b232 100755
--- a/configure
+++ b/configure
@@ -519,7 +519,7 @@ EOF
if compile_prog "" "-liberty" ; then
LIBS="-liberty $LIBS"
fi
- prefix="c:/Program Files/Qemu"
+ prefix="c:/Program Files/QEMU"
mandir="\${prefix}"
datadir="\${prefix}"
docdir="\${prefix}"
diff --git a/qemu-doc.texi b/qemu-doc.texi
index d18dff0..9e07ba6 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2709,9 +2709,9 @@ MinGW's default header and linker search paths.
@file{make}. If you have problems using SDL, verify that
@file{sdl-config} can be launched from the MSYS command line.
- at item You can install QEMU in @file{Program Files/Qemu} by typing
+ at item You can install QEMU in @file{Program Files/QEMU} by typing
@file{make install}. Don't forget to copy @file{SDL.dll} in
- at file{Program Files/Qemu}.
+ at file{Program Files/QEMU}.
@end itemize
@@ -2745,7 +2745,7 @@ The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-ming
MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}.
We set the @code{PATH} environment variable to ensure the MinGW version of @file{sdl-config} is used and
use --cross-prefix to specify the name of the cross compiler.
-You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/Qemu}.
+You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/QEMU}.
Under Fedora Linux, you can run:
@example
commit 6576b74b0ba068f252cc23c5a541c59621270483
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Apr 7 09:23:37 2012 +0200
Replace Qemu by QEMU in internal documentation
The official spelling is QEMU.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/CODING_STYLE b/CODING_STYLE
index 7c82d4d..dcbce28 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -1,4 +1,4 @@
-Qemu Coding Style
+QEMU Coding Style
=================
Please use the script checkpatch.pl in the scripts directory to check
diff --git a/docs/ccid.txt b/docs/ccid.txt
index b8e504a..450a66a 100644
--- a/docs/ccid.txt
+++ b/docs/ccid.txt
@@ -1,4 +1,4 @@
-Qemu CCID Device Documentation.
+QEMU CCID Device Documentation.
Contents
1. USB CCID device
diff --git a/docs/specs/ivshmem_device_spec.txt b/docs/specs/ivshmem_device_spec.txt
index 23dd2ba..667a862 100644
--- a/docs/specs/ivshmem_device_spec.txt
+++ b/docs/specs/ivshmem_device_spec.txt
@@ -24,7 +24,7 @@ The device currently supports 4 registers of 32-bits each. Registers
are used for synchronization between guests sharing the same memory object when
interrupts are supported (this requires using the shared memory server).
-The server assigns each VM an ID number and sends this ID number to the Qemu
+The server assigns each VM an ID number and sends this ID number to the QEMU
process when the guest starts.
enum ivshmem_registers {
diff --git a/target-alpha/STATUS b/target-alpha/STATUS
index 742e370..6c97445 100644
--- a/target-alpha/STATUS
+++ b/target-alpha/STATUS
@@ -4,7 +4,7 @@ Alpha emulation structure:
cpu.h : CPU definitions globally exported
exec.h : CPU definitions used only for translated code execution
helper.c : helpers that can be called either by the translated code
- or the Qemu core, including the exception handler.
+ or the QEMU core, including the exception handler.
op_helper.c : helpers that can be called only from TCG
helper.h : TCG helpers prototypes
translate.c : Alpha instructions to micro-operations translator
diff --git a/target-mips/TODO b/target-mips/TODO
index 9101881..2a3546f 100644
--- a/target-mips/TODO
+++ b/target-mips/TODO
@@ -16,7 +16,7 @@ General
Existing documentation is x86-centric.
- Reverse endianness bit not implemented
- The TLB emulation is very inefficient:
- Qemu's softmmu implements a x86-style MMU, with separate entries
+ QEMU's softmmu implements a x86-style MMU, with separate entries
for read/write/execute, a TLB index which is just a modulo of the
virtual address, and a set of TLBs for each user/kernel/supervisor
MMU mode.
@@ -25,7 +25,7 @@ General
up to 256 ASID tags as additional matching criterion (which roughly
equates to 256 MMU modes). It also has a global flag which causes
entries to match regardless of ASID.
- To cope with these differences, Qemu currently flushes the TLB at
+ To cope with these differences, QEMU currently flushes the TLB at
each ASID change. Using the MMU modes to implement ASIDs hinges on
implementing the global bit efficiently.
- save/restore of the CPU state is not implemented (see machine.c).
commit 071c93945825dcf8b8ec0d81f09e631d7c96142d
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Apr 7 09:23:36 2012 +0200
Replace Qemu by QEMU in user visible documentation
The official spelling is QEMU.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/fsdev/virtfs-proxy-helper.texi b/fsdev/virtfs-proxy-helper.texi
index faa0434..e60e3b9 100644
--- a/fsdev/virtfs-proxy-helper.texi
+++ b/fsdev/virtfs-proxy-helper.texi
@@ -24,7 +24,7 @@ in non-root mode, but doing privileged operations using socket IO.
Proxy helper(a stand alone binary part of qemu) is invoked with
root privileges. Proxy helper chroots into 9p export path and creates
a socket pair or a named socket based on the command line parameter.
-Qemu and proxy helper communicate using this socket. QEMU proxy fs
+QEMU and proxy helper communicate using this socket. QEMU proxy fs
driver sends filesystem request to proxy helper and receives the
response from it.
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 83b2ad5..d18dff0 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -968,7 +968,7 @@ monitor (@pxref{pcsys_keys}).
QEMU emulates a PCI UHCI USB controller. You can virtually plug
virtual USB devices or real host USB devices (experimental, works only
-on Linux hosts). Qemu will automatically create and connect virtual USB hubs
+on Linux hosts). QEMU will automatically create and connect virtual USB hubs
as necessary to connect multiple USB devices.
@menu
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 44996cc..6955d90 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -6,7 +6,7 @@ usage: qemu-nbd [OPTION]... @var{filename}
@c man begin DESCRIPTION
-Export Qemu disk image using NBD protocol.
+Export QEMU disk image using NBD protocol.
@c man end
diff --git a/qemu-options.hx b/qemu-options.hx
index f72f9a0..a169792 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1310,7 +1310,7 @@ and a @var{name} can be assigned for use in monitor commands.
Optionally, for PCI cards, you can specify the number @var{v} of MSI-X vectors
that the card should have; this option currently only affects virtio cards; set
@var{v} = 0 to disable MSI-X. If no @option{-net} option is specified, a single
-NIC is created. Qemu can emulate several different models of network card.
+NIC is created. QEMU can emulate several different models of network card.
Valid values for @var{type} are
@code{virtio}, @code{i82551}, @code{i82557b}, @code{i82559er},
@code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139},
@@ -2133,7 +2133,7 @@ activates telnet remote echo and single char transfer, then you can
use the following options to step up a netcat redirector to allow
telnet on port 5555 to access the qemu port.
@table @code
- at item Qemu Options:
+ at item QEMU Options:
-serial udp::4555@@:4556
@item netcat options:
-u -P 4555 -L 0.0.0.0:4556 -t -p 5555 -I -T
commit 97a33880e7c06332ea3498437c70a903cbbfe361
Author: Wanpeng Li <liwp at linux.vnet.ibm.com>
Date: Fri Apr 6 15:52:09 2012 +0800
remove useless comments in dma
This comment is useless, just removes it and makes the codes clear.
Signed-off-by: Wanpeng Li <liwp at linux.vnet.ibm.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/dma.h b/dma.h
index 20e86d2..5bd1fc8 100644
--- a/dma.h
+++ b/dma.h
@@ -11,7 +11,6 @@
#define DMA_H
#include <stdio.h>
-//#include "cpu.h"
#include "hw/hw.h"
#include "block.h"
commit 3b2aba2f1309cebbcb72a5f006479f2467aa4e9f
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Apr 7 11:48:39 2012 +0200
tci: Support targets with CONFIG_TCG_PASS_AREG0 (fix broken build)
Builds with --enable-tcg-interpreter failed because more and more
targets (currently alpha and sparc) replaced the global env in AREG0
by function parameters.
Convert the TCG interpreter to use the new helper functions and add
defines for those targets which still use AREG0.
Cc: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tci.c b/tci.c
index 70e7bfb..c43fe7d 100644
--- a/tci.c
+++ b/tci.c
@@ -63,6 +63,17 @@ void *tci_tb_ptr;
static tcg_target_ulong tci_reg[TCG_TARGET_NB_REGS];
+#if !defined(CONFIG_TCG_PASS_AREG0)
+# define helper_ldb_mmu(env, addr, mmu_idx) __ldb_mmu(addr, mmu_idx)
+# define helper_ldw_mmu(env, addr, mmu_idx) __ldw_mmu(addr, mmu_idx)
+# define helper_ldl_mmu(env, addr, mmu_idx) __ldl_mmu(addr, mmu_idx)
+# define helper_ldq_mmu(env, addr, mmu_idx) __ldq_mmu(addr, mmu_idx)
+# define helper_stb_mmu(env, addr, val, mmu_idx) __stb_mmu(addr, val, mmu_idx)
+# define helper_stw_mmu(env, addr, val, mmu_idx) __stw_mmu(addr, val, mmu_idx)
+# define helper_stl_mmu(env, addr, val, mmu_idx) __stl_mmu(addr, val, mmu_idx)
+# define helper_stq_mmu(env, addr, val, mmu_idx) __stq_mmu(addr, val, mmu_idx)
+#endif /* !CONFIG_TCG_PASS_AREG0 */
+
static tcg_target_ulong tci_read_reg(TCGReg index)
{
assert(index < ARRAY_SIZE(tci_reg));
@@ -1049,7 +1060,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
t0 = *tb_ptr++;
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
- tmp8 = __ldb_mmu(taddr, tci_read_i(&tb_ptr));
+ tmp8 = helper_ldb_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1061,7 +1072,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
t0 = *tb_ptr++;
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
- tmp8 = __ldb_mmu(taddr, tci_read_i(&tb_ptr));
+ tmp8 = helper_ldb_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1073,7 +1084,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
t0 = *tb_ptr++;
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
- tmp16 = __ldw_mmu(taddr, tci_read_i(&tb_ptr));
+ tmp16 = helper_ldw_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1085,7 +1096,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
t0 = *tb_ptr++;
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
- tmp16 = __ldw_mmu(taddr, tci_read_i(&tb_ptr));
+ tmp16 = helper_ldw_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1098,7 +1109,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
t0 = *tb_ptr++;
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
- tmp32 = __ldl_mmu(taddr, tci_read_i(&tb_ptr));
+ tmp32 = helper_ldl_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1110,7 +1121,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
t0 = *tb_ptr++;
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
- tmp32 = __ldl_mmu(taddr, tci_read_i(&tb_ptr));
+ tmp32 = helper_ldl_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1123,7 +1134,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
t0 = *tb_ptr++;
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
- tmp32 = __ldl_mmu(taddr, tci_read_i(&tb_ptr));
+ tmp32 = helper_ldl_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1138,7 +1149,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
#endif
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
- tmp64 = __ldq_mmu(taddr, tci_read_i(&tb_ptr));
+ tmp64 = helper_ldq_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1154,7 +1165,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
t2 = tci_read_i(&tb_ptr);
- __stb_mmu(taddr, t0, t2);
+ helper_stb_mmu(env, taddr, t0, t2);
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1166,7 +1177,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
t2 = tci_read_i(&tb_ptr);
- __stw_mmu(taddr, t0, t2);
+ helper_stw_mmu(env, taddr, t0, t2);
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1178,7 +1189,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
t2 = tci_read_i(&tb_ptr);
- __stl_mmu(taddr, t0, t2);
+ helper_stl_mmu(env, taddr, t0, t2);
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
@@ -1190,7 +1201,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
taddr = tci_read_ulong(&tb_ptr);
#ifdef CONFIG_SOFTMMU
t2 = tci_read_i(&tb_ptr);
- __stq_mmu(taddr, tmp64, t2);
+ helper_stq_mmu(env, taddr, tmp64, t2);
#else
host_addr = (tcg_target_ulong)taddr;
assert(taddr == host_addr);
commit adcd61f7fcd5a24e65b2ec087bfae2356805993b
Merge: 6375e09... d8fd295...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Apr 7 11:45:25 2012 +0000
Merge branch 'linux-user-for-upstream' of git://git.linaro.org/people/rikuvoipio/qemu
* 'linux-user-for-upstream' of git://git.linaro.org/people/rikuvoipio/qemu:
Userspace ARM BE8 support
elf.h: Update EF_ARM_ constants to newer ABI versions
arm-linux-user: fix elfload.c's AT_HWCAP to reflect cpu features.
linux-user/arm/syscall_nr.h: Add syscall number for ppoll
linux-user: Add support for prctl PR_GET_NAME and PR_SET_NAME
linux-user/syscall.c: Fix indentation in prctl handling
linux-user: reserve 4GB of vmem for 32-on-64
linux-user: resolve reserved_va vma downwards
linux-user: take RESERVED_VA into account for g2h_valid()
linux-user: fix fallocate
linux-user: Add ioctl for BLKBSZGET
linux-user: add BLKSSZGET ioctl wrapper
linux-user: fix BLK ioctl arguments
linux-user: add struct old_dev_t compat
linux-user: implement device mapper ioctls
linux-user: target_argv is placed on ts->bprm->argv and can't be freed()
linux-user: improve fake /proc/self/stat making `ps` not segfault.
commit 6375e09e79964fa6eac3e8426d25c8b759185482
Author: Stefan Weil <sw at weilnetz.de>
Date: Fri Apr 6 22:26:15 2012 +0200
w64: Fix data type of tb_next and other variables used for host addresses
QEMU host addresses must use uintptr_t to be portable for hosts with
an unusual size of long (w64).
tb_jmp_offset is an uint16_t value, therefore the local variable offset
in function tb_set_jmp_target was changed from unsigned long to uint16_t.
The type cast to long in function tb_add_jump now also uses uintptr_t.
For the bit operation used here, the signedness of the type cast does
not matter.
Some remaining unsigned long values are either only used for ARM assembler
code or will be fixed in a later patch for PPC.
v2:
Fix signature of tb_find_pc in exec.c, too (hint from Blue Swirl, thanks).
There remain lots of other long / unsigned long in exec.c which must be
replaced by uintptr_t. This will be done in a separate patch. Here
only one of these type casts is fixed.
v3:
Also fix signature of page_unprotect.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/exec-all.h b/exec-all.h
index 93a5b22..a6d6519 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -85,7 +85,7 @@ void cpu_gen_init(void);
int cpu_gen_code(CPUArchState *env, struct TranslationBlock *tb,
int *gen_code_size_ptr);
int cpu_restore_state(struct TranslationBlock *tb,
- CPUArchState *env, unsigned long searched_pc);
+ CPUArchState *env, uintptr_t searched_pc);
void cpu_resume_from_signal(CPUArchState *env1, void *puc);
void cpu_io_recompile(CPUArchState *env, void *retaddr);
TranslationBlock *tb_gen_code(CPUArchState *env,
@@ -93,7 +93,7 @@ TranslationBlock *tb_gen_code(CPUArchState *env,
int cflags);
void cpu_exec_init(CPUArchState *env);
void QEMU_NORETURN cpu_loop_exit(CPUArchState *env1);
-int page_unprotect(target_ulong address, unsigned long pc, void *puc);
+int page_unprotect(target_ulong address, uintptr_t pc, void *puc);
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
int is_cpu_write_access);
void tlb_flush_page(CPUArchState *env, target_ulong addr);
@@ -150,7 +150,7 @@ struct TranslationBlock {
#ifdef USE_DIRECT_JUMP
uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
#else
- unsigned long tb_next[2]; /* address of jump generated code */
+ uintptr_t tb_next[2]; /* address of jump generated code */
#endif
/* list of TBs jumping to this one. This is a circular list using
the two least significant bits of the pointers to tell what is
@@ -202,14 +202,14 @@ static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr);
#define tb_set_jmp_target1 ppc_tb_set_jmp_target
#elif defined(__i386__) || defined(__x86_64__)
-static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
+static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
{
/* patch the branch destination */
*(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
/* no need to flush icache explicitly */
}
#elif defined(__arm__)
-static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
+static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
{
#if !QEMU_GNUC_PREREQ(4, 1)
register unsigned long _beg __asm ("a1");
@@ -237,19 +237,17 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
#endif
static inline void tb_set_jmp_target(TranslationBlock *tb,
- int n, unsigned long addr)
+ int n, uintptr_t addr)
{
- unsigned long offset;
-
- offset = tb->tb_jmp_offset[n];
- tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
+ uint16_t offset = tb->tb_jmp_offset[n];
+ tb_set_jmp_target1((uintptr_t)(tb->tc_ptr + offset), addr);
}
#else
/* set the jump target */
static inline void tb_set_jmp_target(TranslationBlock *tb,
- int n, unsigned long addr)
+ int n, uintptr_t addr)
{
tb->tb_next[n] = addr;
}
@@ -262,15 +260,15 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
/* NOTE: this test is only needed for thread safety */
if (!tb->jmp_next[n]) {
/* patch the native jump address */
- tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
+ tb_set_jmp_target(tb, n, (uintptr_t)tb_next->tc_ptr);
/* add in TB jmp circular list */
tb->jmp_next[n] = tb_next->jmp_first;
- tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
+ tb_next->jmp_first = (TranslationBlock *)((uintptr_t)(tb) | (n));
}
}
-TranslationBlock *tb_find_pc(unsigned long pc_ptr);
+TranslationBlock *tb_find_pc(uintptr_t pc_ptr);
#include "qemu-lock.h"
@@ -288,13 +286,14 @@ extern void *tci_tb_ptr;
# define GETPC() tci_tb_ptr
# endif
#elif defined(__s390__) && !defined(__s390x__)
-# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1))
+# define GETPC() \
+ ((void *)(((uintptr_t)__builtin_return_address(0) & 0x7fffffffUL) - 1))
#elif defined(__arm__)
/* Thumb return addresses have the low bit set, so we need to subtract two.
This is still safe in ARM mode because instructions are 4 bytes. */
-# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2))
+# define GETPC() ((void *)((uintptr_t)__builtin_return_address(0) - 2))
#else
-# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1))
+# define GETPC() ((void *)((uintptr_t)__builtin_return_address(0) - 1))
#endif
#if !defined(CONFIG_USER_ONLY)
diff --git a/exec.c b/exec.c
index 6731ab8..03d3a6b 100644
--- a/exec.c
+++ b/exec.c
@@ -1380,7 +1380,7 @@ void tb_link_page(TranslationBlock *tb,
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
tb[1].tc_ptr. Return NULL if not found */
-TranslationBlock *tb_find_pc(unsigned long tc_ptr)
+TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
{
int m_min, m_max, m;
unsigned long v;
@@ -2502,7 +2502,7 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
/* called from signal handler: invalidate the code and unprotect the
page. Return TRUE if the fault was successfully handled. */
-int page_unprotect(target_ulong address, unsigned long pc, void *puc)
+int page_unprotect(target_ulong address, uintptr_t pc, void *puc)
{
unsigned int prot;
PageDesc *p;
@@ -4484,7 +4484,7 @@ void cpu_io_recompile(CPUArchState *env, void *retaddr)
target_ulong pc, cs_base;
uint64_t flags;
- tb = tb_find_pc((unsigned long)retaddr);
+ tb = tb_find_pc((uintptr_t)retaddr);
if (!tb) {
cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
retaddr);
diff --git a/translate-all.c b/translate-all.c
index 8c7d303..5bd2d37 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -109,11 +109,11 @@ int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr
/* The cpu state corresponding to 'searched_pc' is restored.
*/
int cpu_restore_state(TranslationBlock *tb,
- CPUArchState *env, unsigned long searched_pc)
+ CPUArchState *env, uintptr_t searched_pc)
{
TCGContext *s = &tcg_ctx;
int j;
- unsigned long tc_ptr;
+ uintptr_t tc_ptr;
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
@@ -133,7 +133,7 @@ int cpu_restore_state(TranslationBlock *tb,
}
/* find opc index corresponding to search_pc */
- tc_ptr = (unsigned long)tb->tc_ptr;
+ tc_ptr = (uintptr_t)tb->tc_ptr;
if (searched_pc < tc_ptr)
return -1;
commit 760e141613f5f7c09f5c141658f1e7c23b4a5c33
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Thu Apr 5 19:12:35 2012 +0100
softfloat: roundAndPackInt{32, 64}: Don't assume int32 is 32 bits
Fix code in roundAndPackInt32 that assumed that int32 was only
32 bits, by simply using int32_t instead. Fix the parallel bug
in roundAndPackInt64 as well, although that one is only theoretical
since it's unlikely that int64 will ever be more than 64 bits.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 074fbc3..d37090a 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -117,7 +117,7 @@ static int32 roundAndPackInt32( flag zSign, uint64_t absZ STATUS_PARAM)
int8 roundingMode;
flag roundNearestEven;
int8 roundIncrement, roundBits;
- int32 z;
+ int32_t z;
roundingMode = STATUS(float_rounding_mode);
roundNearestEven = ( roundingMode == float_round_nearest_even );
@@ -166,7 +166,7 @@ static int64 roundAndPackInt64( flag zSign, uint64_t absZ0, uint64_t absZ1 STATU
{
int8 roundingMode;
flag roundNearestEven, increment;
- int64 z;
+ int64_t z;
roundingMode = STATUS(float_rounding_mode);
roundNearestEven = ( roundingMode == float_round_nearest_even );
commit b3a6a2e0417c78ec5491347eb85a7d125a5fefdc
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Thu Apr 5 19:12:34 2012 +0100
softfloat: float*_to_int32_round_to_zero: don't assume int32 is 32 bits
Code in the float64_to_int32_round_to_zero() function was assuming
that int32 would not be wider than 32 bits; this meant it might
not correctly detect the overflow case. We take the simple approach
of using int32_t. Also fix equivalent issues in the functions
for other float sizes.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 81a7d1a..074fbc3 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -1378,7 +1378,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
flag aSign;
int16 aExp, shiftCount;
uint32_t aSig;
- int32 z;
+ int32_t z;
a = float32_squash_input_denormal(a STATUS_VAR);
aSig = extractFloat32Frac( a );
@@ -2762,7 +2762,7 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
flag aSign;
int16 aExp, shiftCount;
uint64_t aSig, savedASig;
- int32 z;
+ int32_t z;
a = float64_squash_input_denormal(a STATUS_VAR);
aSig = extractFloat64Frac( a );
@@ -4248,7 +4248,7 @@ int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM )
flag aSign;
int32 aExp, shiftCount;
uint64_t aSig, savedASig;
- int32 z;
+ int32_t z;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
@@ -5277,7 +5277,7 @@ int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM )
flag aSign;
int32 aExp, shiftCount;
uint64_t aSig0, aSig1, savedASig;
- int32 z;
+ int32_t z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
commit a52d28afb4e825a5b28815370a268904a4c6dc11
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 5 13:01:54 2012 +0200
configure: require glib 2.12, 2.20 for mingw32
These are pretty sane requirements to move forward with glib usage.
2.12 is the version found in RHEL/CentOS 5, and 2.20 is the
first version to support g_poll. Without g_poll, we cannot
integrate well with the glib main loop.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/configure b/configure
index 4b3adc9..6f850a6 100755
--- a/configure
+++ b/configure
@@ -1993,13 +1993,21 @@ fi
##########################################
# glib support probe
-if $pkg_config --modversion gthread-2.0 > /dev/null 2>&1 ; then
+
+if test "$mingw32" = yes; then
+ # g_poll is required in order to integrate with the glib main loop.
+ glib_req_ver=2.20
+else
+ glib_req_ver=2.12
+fi
+if $pkg_config --atleast-version=$glib_req_ver gthread-2.0 > /dev/null 2>&1
+then
glib_cflags=`$pkg_config --cflags gthread-2.0 2>/dev/null`
glib_libs=`$pkg_config --libs gthread-2.0 2>/dev/null`
LIBS="$glib_libs $LIBS"
libs_qga="$glib_libs $libs_qga"
else
- echo "glib-2.0 required to compile QEMU"
+ echo "glib-$glib_req_ver required to compile QEMU"
exit 1
fi
commit ea26ce765cb661a13e4055f38744036a19465e87
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 20 10:49:21 2012 +0100
main-loop: integrate glib sources for w32
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/main-loop.c b/main-loop.c
index 4d02568..7e163f9 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -221,11 +221,10 @@ int main_loop_init(void)
static fd_set rfds, wfds, xfds;
static int nfds;
static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
-
-#ifndef _WIN32
static int n_poll_fds;
static int max_priority;
+#ifndef _WIN32
static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
fd_set *xfds, int *cur_timeout)
{
@@ -403,6 +402,7 @@ void qemu_fd_register(int fd)
static int os_host_main_loop_wait(int timeout)
{
+ GMainContext *context = g_main_context_default();
int ret, i;
PollingEntry *pe;
WaitObjects *w = &wait_objects;
@@ -424,17 +424,22 @@ static int os_host_main_loop_wait(int timeout)
}
}
+ g_main_context_prepare(context, &max_priority);
+ n_poll_fds = g_main_context_query(context, max_priority, &timeout,
+ poll_fds, ARRAY_SIZE(poll_fds));
+ g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
+
for (i = 0; i < w->num; i++) {
- poll_fds[i].fd = (DWORD) w->events[i];
- poll_fds[i].events = G_IO_IN;
+ poll_fds[n_poll_fds + i].fd = (DWORD) w->events[i];
+ poll_fds[n_poll_fds + i].events = G_IO_IN;
}
qemu_mutex_unlock_iothread();
- ret = g_poll(poll_fds, w->num, timeout);
+ ret = g_poll(poll_fds, n_poll_fds + w->num, timeout);
qemu_mutex_lock_iothread();
if (ret > 0) {
for (i = 0; i < w->num; i++) {
- w->revents[i] = poll_fds[i].revents;
+ w->revents[i] = poll_fds[n_poll_fds + i].revents;
}
for (i = 0; i < w->num; i++) {
if (w->revents[i] && w->func[i]) {
@@ -443,6 +448,10 @@ static int os_host_main_loop_wait(int timeout)
}
}
+ if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
+ g_main_context_dispatch(context);
+ }
+
/* If an edge-triggered socket event occurred, select will return a
* positive result on the next iteration. We do not need to do anything
* here.
commit 06ac7d49797daf8a5c05c7d25db0b205efda8e30
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 20 10:49:20 2012 +0100
main-loop: replace WaitForMultipleObjects with g_poll
On w32, glib implements g_poll using WaitForMultipleObjects
or MsgWaitForMultipleObjects. This means that we can simplify
our code by switching to g_poll, and at the same time prepare for
adding back glib sources.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/main-loop.c b/main-loop.c
index 7364074..4d02568 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -220,9 +220,9 @@ int main_loop_init(void)
static fd_set rfds, wfds, xfds;
static int nfds;
+static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
#ifndef _WIN32
-static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
static int n_poll_fds;
static int max_priority;
@@ -351,6 +351,7 @@ void qemu_del_polling_cb(PollingFunc *func, void *opaque)
/* Wait objects support */
typedef struct WaitObjects {
int num;
+ int revents[MAXIMUM_WAIT_OBJECTS + 1];
HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
@@ -367,6 +368,7 @@ int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
w->events[w->num] = handle;
w->func[w->num] = func;
w->opaque[w->num] = opaque;
+ w->revents[w->num] = 0;
w->num++;
return 0;
}
@@ -385,6 +387,7 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
w->events[i] = w->events[i + 1];
w->func[i] = w->func[i + 1];
w->opaque[i] = w->opaque[i + 1];
+ w->revents[i] = w->revents[i + 1];
}
}
if (found) {
@@ -400,9 +403,8 @@ void qemu_fd_register(int fd)
static int os_host_main_loop_wait(int timeout)
{
- int ret, ret2, i;
+ int ret, i;
PollingEntry *pe;
- int err;
WaitObjects *w = &wait_objects;
static struct timeval tv0;
@@ -422,33 +424,25 @@ static int os_host_main_loop_wait(int timeout)
}
}
+ for (i = 0; i < w->num; i++) {
+ poll_fds[i].fd = (DWORD) w->events[i];
+ poll_fds[i].events = G_IO_IN;
+ }
+
qemu_mutex_unlock_iothread();
- ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
+ ret = g_poll(poll_fds, w->num, timeout);
qemu_mutex_lock_iothread();
- if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
- if (w->func[ret - WAIT_OBJECT_0]) {
- w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+ if (ret > 0) {
+ for (i = 0; i < w->num; i++) {
+ w->revents[i] = poll_fds[i].revents;
}
-
- /* Check for additional signaled events */
- for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
- /* Check if event is signaled */
- ret2 = WaitForSingleObject(w->events[i], 0);
- if (ret2 == WAIT_OBJECT_0) {
- if (w->func[i]) {
- w->func[i](w->opaque[i]);
- }
- } else if (ret2 != WAIT_TIMEOUT) {
- err = GetLastError();
- fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+ for (i = 0; i < w->num; i++) {
+ if (w->revents[i] && w->func[i]) {
+ w->func[i](w->opaque[i]);
}
}
- } else if (ret != WAIT_TIMEOUT) {
- err = GetLastError();
- fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
}
-
/* If an edge-triggered socket event occurred, select will return a
* positive result on the next iteration. We do not need to do anything
* here.
commit d3385eb448e38f828c78f8f68ec5d79c66a58b5d
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 20 10:49:19 2012 +0100
main-loop: interrupt wait when data arrives on a socket
Right now, the main loop is not interrupted when data arrives on a
socket. To fix this, register each socket to interrupt the main loop
with WSAEventSelect. This does not replace select, it only communicates
a change in socket state that requires a select call.
Since the interrupt fires only once per recv call, or only once
after a send call returns EWOULDBLOCK we can activate it on all events
unconditionally. If QEMU is momentarily uninterested on some condition,
the main loop will not busy wait. Instead, it may get one extra wakeup,
but then it will ignore the condition until progress occurs and/or
qemu_set_fd_handler is called to set a callback. At this point the
condition will be tested via select and the callback will be invoked
even if it is still disabled on the event.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/main-loop.c b/main-loop.c
index dc6bdb5..7364074 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -392,10 +392,18 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
}
}
+void qemu_fd_register(int fd)
+{
+ WSAEventSelect(fd, qemu_event_handle, FD_READ | FD_ACCEPT | FD_CLOSE |
+ FD_CONNECT | FD_WRITE | FD_OOB);
+}
+
static int os_host_main_loop_wait(int timeout)
{
int ret, ret2, i;
PollingEntry *pe;
+ int err;
+ WaitObjects *w = &wait_objects;
static struct timeval tv0;
/* XXX: need to suppress polling by better using win32 events */
@@ -403,38 +411,49 @@ static int os_host_main_loop_wait(int timeout)
for (pe = first_polling_entry; pe != NULL; pe = pe->next) {
ret |= pe->func(pe->opaque);
}
- if (ret == 0) {
- int err;
- WaitObjects *w = &wait_objects;
+ if (ret != 0) {
+ return ret;
+ }
- qemu_mutex_unlock_iothread();
- ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
- qemu_mutex_lock_iothread();
- if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
- if (w->func[ret - WAIT_OBJECT_0]) {
- w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
- }
+ if (nfds >= 0) {
+ ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0);
+ if (ret != 0) {
+ timeout = 0;
+ }
+ }
- /* Check for additional signaled events */
- for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
- /* Check if event is signaled */
- ret2 = WaitForSingleObject(w->events[i], 0);
- if (ret2 == WAIT_OBJECT_0) {
- if (w->func[i]) {
- w->func[i](w->opaque[i]);
- }
- } else if (ret2 != WAIT_TIMEOUT) {
- err = GetLastError();
- fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+ qemu_mutex_unlock_iothread();
+ ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
+ qemu_mutex_lock_iothread();
+ if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+ if (w->func[ret - WAIT_OBJECT_0]) {
+ w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+ }
+
+ /* Check for additional signaled events */
+ for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+ /* Check if event is signaled */
+ ret2 = WaitForSingleObject(w->events[i], 0);
+ if (ret2 == WAIT_OBJECT_0) {
+ if (w->func[i]) {
+ w->func[i](w->opaque[i]);
}
+ } else if (ret2 != WAIT_TIMEOUT) {
+ err = GetLastError();
+ fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
}
- } else if (ret != WAIT_TIMEOUT) {
- err = GetLastError();
- fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
}
+ } else if (ret != WAIT_TIMEOUT) {
+ err = GetLastError();
+ fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
}
- ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0);
+
+ /* If an edge-triggered socket event occurred, select will return a
+ * positive result on the next iteration. We do not need to do anything
+ * here.
+ */
+
return ret;
}
#endif
diff --git a/main-loop.h b/main-loop.h
index 4987041..e743aa0 100644
--- a/main-loop.h
+++ b/main-loop.h
@@ -359,6 +359,7 @@ void qemu_mutex_unlock_iothread(void);
/* internal interfaces */
+void qemu_fd_register(int fd);
void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
diff --git a/oslib-win32.c b/oslib-win32.c
index ce3021e..ffbc6d0 100644
--- a/oslib-win32.c
+++ b/oslib-win32.c
@@ -28,6 +28,7 @@
#include <windows.h>
#include "config-host.h"
#include "sysemu.h"
+#include "main-loop.h"
#include "trace.h"
#include "qemu_socket.h"
@@ -76,6 +77,7 @@ void qemu_vfree(void *ptr)
void socket_set_block(int fd)
{
unsigned long opt = 0;
+ WSAEventSelect(fd, NULL, 0);
ioctlsocket(fd, FIONBIO, &opt);
}
@@ -83,6 +85,7 @@ void socket_set_nonblock(int fd)
{
unsigned long opt = 1;
ioctlsocket(fd, FIONBIO, &opt);
+ qemu_fd_register(fd);
}
int inet_aton(const char *cp, struct in_addr *ia)
commit 15455536df5ef652759ccf465d5e6f73acb493df
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 20 10:49:18 2012 +0100
main-loop: disable fd_set-based glib integration under w32
Using select with glib pollfds is wrong under w32. Restrict
the code to the POSIX case.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/main-loop.c b/main-loop.c
index a3fd993..dc6bdb5 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -218,7 +218,10 @@ int main_loop_init(void)
return 0;
}
+static fd_set rfds, wfds, xfds;
+static int nfds;
+#ifndef _WIN32
static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
static int n_poll_fds;
static int max_priority;
@@ -286,7 +289,29 @@ static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
}
}
-#ifdef _WIN32
+static int os_host_main_loop_wait(int timeout)
+{
+ struct timeval tv;
+ int ret;
+
+ glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
+
+ if (timeout > 0) {
+ qemu_mutex_unlock_iothread();
+ }
+
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+
+ if (timeout > 0) {
+ qemu_mutex_lock_iothread();
+ }
+
+ glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+ return ret;
+}
+#else
/***********************************************************/
/* Polling handling */
@@ -367,10 +392,11 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
}
}
-static void os_host_main_loop_wait(int *timeout)
+static int os_host_main_loop_wait(int timeout)
{
int ret, ret2, i;
PollingEntry *pe;
+ static struct timeval tv0;
/* XXX: need to suppress polling by better using win32 events */
ret = 0;
@@ -382,7 +408,7 @@ static void os_host_main_loop_wait(int *timeout)
WaitObjects *w = &wait_objects;
qemu_mutex_unlock_iothread();
- ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
+ ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
qemu_mutex_lock_iothread();
if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
if (w->func[ret - WAIT_OBJECT_0]) {
@@ -408,20 +434,14 @@ static void os_host_main_loop_wait(int *timeout)
}
}
- *timeout = 0;
-}
-#else
-static inline void os_host_main_loop_wait(int *timeout)
-{
+ ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0);
+ return ret;
}
#endif
int main_loop_wait(int nonblocking)
{
- fd_set rfds, wfds, xfds;
- int ret, nfds;
- struct timeval tv;
- int timeout;
+ int ret, timeout;
if (nonblocking) {
timeout = 0;
@@ -441,24 +461,7 @@ int main_loop_wait(int nonblocking)
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
#endif
qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
-
- glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
- os_host_main_loop_wait(&timeout);
-
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
-
- if (timeout > 0) {
- qemu_mutex_unlock_iothread();
- }
-
- ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
-
- if (timeout > 0) {
- qemu_mutex_lock_iothread();
- }
-
- glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+ ret = os_host_main_loop_wait(timeout);
qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
#ifdef CONFIG_SLIRP
slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
commit 4dae83aeac63863af6b59f58552da68b35b1a40d
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 20 10:49:17 2012 +0100
main loop: use msec-based timeout in glib_select_fill
The timeval-based timeout is not needed until we actually invoke select,
so compute it only then. Also group the two calls that modify the
timeout, glib_select_fill and os_host_main_loop_wait.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/main-loop.c b/main-loop.c
index db23de0..a3fd993 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -224,11 +224,11 @@ static int n_poll_fds;
static int max_priority;
static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
- fd_set *xfds, struct timeval *tv)
+ fd_set *xfds, int *cur_timeout)
{
GMainContext *context = g_main_context_default();
int i;
- int timeout = 0, cur_timeout;
+ int timeout = 0;
g_main_context_prepare(context, &max_priority);
@@ -253,10 +253,8 @@ static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
}
}
- cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000);
- if (timeout >= 0 && timeout < cur_timeout) {
- tv->tv_sec = timeout / 1000;
- tv->tv_usec = (timeout % 1000) * 1000;
+ if (timeout >= 0 && timeout < *cur_timeout) {
+ *cur_timeout = timeout;
}
}
@@ -432,11 +430,6 @@ int main_loop_wait(int nonblocking)
qemu_bh_update_timeout(&timeout);
}
- os_host_main_loop_wait(&timeout);
-
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
-
/* poll any events */
/* XXX: separate device handlers from system ones */
nfds = -1;
@@ -448,7 +441,12 @@ int main_loop_wait(int nonblocking)
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
#endif
qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
- glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv);
+
+ glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
+ os_host_main_loop_wait(&timeout);
+
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
if (timeout > 0) {
qemu_mutex_unlock_iothread();
commit ab7ab3d74c357e73a37b241fba27ea7f0595c085
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Apr 5 01:29:40 2012 +0200
target-sparc: QOM'ify CPU
Embed CPUSPARCState as first member of SPARCCPU.
Drop cpu_sparc_close() in favor of object_delete() and a finalizer.
Let cpu_state_reset() call cpu_reset().
Make TYPE_SPARC_CPU non-abstract for now.
Distinguish between "sparc-cpu" and "sparc64-cpu".
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h
new file mode 100644
index 0000000..3d3ac0f
--- /dev/null
+++ b/target-sparc/cpu-qom.h
@@ -0,0 +1,75 @@
+/*
+ * QEMU SPARC CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_SPARC_CPU_QOM_H
+#define QEMU_SPARC_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#ifdef TARGET_SPARC64
+#define TYPE_SPARC_CPU "sparc64-cpu"
+#else
+#define TYPE_SPARC_CPU "sparc-cpu"
+#endif
+
+#define SPARC_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SPARCCPUClass, (klass), TYPE_SPARC_CPU)
+#define SPARC_CPU(obj) \
+ OBJECT_CHECK(SPARCCPU, (obj), TYPE_SPARC_CPU)
+#define SPARC_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SPARCCPUClass, (obj), TYPE_SPARC_CPU)
+
+/**
+ * SPARCCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A SPARC CPU model.
+ */
+typedef struct SPARCCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} SPARCCPUClass;
+
+/**
+ * SPARCCPU:
+ * @env: #CPUSPARCState
+ *
+ * A SPARC CPU.
+ */
+typedef struct SPARCCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUSPARCState env;
+} SPARCCPU;
+
+static inline SPARCCPU *sparc_env_get_cpu(CPUSPARCState *env)
+{
+ return SPARC_CPU(container_of(env, SPARCCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(sparc_env_get_cpu(e))
+
+
+#endif
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 5c03f0b..24f90f1 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -25,11 +25,23 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
void cpu_state_reset(CPUSPARCState *env)
{
+ cpu_reset(ENV_GET_CPU(env));
+}
+
+/* CPUClass::reset() */
+static void sparc_cpu_reset(CPUState *s)
+{
+ SPARCCPU *cpu = SPARC_CPU(s);
+ SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(cpu);
+ CPUSPARCState *env = &cpu->env;
+
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
log_cpu_state(env, 0);
}
+ scc->parent_reset(s);
+
memset(env, 0, offsetof(CPUSPARCState, breakpoints));
tlb_flush(env, 1);
env->cwp = 0;
@@ -99,23 +111,18 @@ static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
return 0;
}
-static void cpu_sparc_close(CPUSPARCState *env)
-{
- g_free(env->def);
- g_free(env);
-}
-
CPUSPARCState *cpu_sparc_init(const char *cpu_model)
{
+ SPARCCPU *cpu;
CPUSPARCState *env;
- env = g_new0(CPUSPARCState, 1);
- cpu_exec_init(env);
+ cpu = SPARC_CPU(object_new(TYPE_SPARC_CPU));
+ env = &cpu->env;
gen_intermediate_code_init(env);
if (cpu_sparc_register(env, cpu_model) < 0) {
- cpu_sparc_close(env);
+ object_delete(OBJECT(cpu));
return NULL;
}
qemu_init_vcpu(env);
@@ -847,3 +854,46 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf,
env->fsr, env->y);
#endif
}
+
+static void sparc_cpu_initfn(Object *obj)
+{
+ SPARCCPU *cpu = SPARC_CPU(obj);
+ CPUSPARCState *env = &cpu->env;
+
+ cpu_exec_init(env);
+}
+
+static void sparc_cpu_uninitfn(Object *obj)
+{
+ SPARCCPU *cpu = SPARC_CPU(obj);
+ CPUSPARCState *env = &cpu->env;
+
+ g_free(env->def);
+}
+
+static void sparc_cpu_class_init(ObjectClass *oc, void *data)
+{
+ SPARCCPUClass *scc = SPARC_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
+
+ scc->parent_reset = cc->reset;
+ cc->reset = sparc_cpu_reset;
+}
+
+static const TypeInfo sparc_cpu_type_info = {
+ .name = TYPE_SPARC_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(SPARCCPU),
+ .instance_init = sparc_cpu_initfn,
+ .instance_finalize = sparc_cpu_uninitfn,
+ .abstract = false,
+ .class_size = sizeof(SPARCCPUClass),
+ .class_init = sparc_cpu_class_init,
+};
+
+static void sparc_cpu_register_types(void)
+{
+ type_register_static(&sparc_cpu_type_info);
+}
+
+type_init(sparc_cpu_register_types)
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 885ad45..865288c 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -691,6 +691,7 @@ static inline void cpu_clone_regs(CPUSPARCState *env, target_ulong newsp)
#endif
#include "cpu-all.h"
+#include "cpu-qom.h"
#ifdef TARGET_SPARC64
/* sun4u.c */
commit 88ca012a1f0bb89d481e506eb4738382062da55f
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Apr 5 01:29:39 2012 +0200
target-sparc: Rename cpu_init.c
Align QOM'ified targets, with a view to simplify Makefile.target.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile.target b/Makefile.target
index 999a968..14c8fa1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -96,7 +96,7 @@ libobj-$(TARGET_ARM) += cpu.o
libobj-$(TARGET_S390X) += cpu.o
ifeq ($(TARGET_BASE_ARCH), sparc)
libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
-libobj-y += cpu_init.o
+libobj-y += cpu.o
endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
new file mode 100644
index 0000000..5c03f0b
--- /dev/null
+++ b/target-sparc/cpu.c
@@ -0,0 +1,849 @@
+/*
+ * Sparc CPU init helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+
+//#define DEBUG_FEATURES
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
+
+void cpu_state_reset(CPUSPARCState *env)
+{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
+ memset(env, 0, offsetof(CPUSPARCState, breakpoints));
+ tlb_flush(env, 1);
+ env->cwp = 0;
+#ifndef TARGET_SPARC64
+ env->wim = 1;
+#endif
+ env->regwptr = env->regbase + (env->cwp * 16);
+ CC_OP = CC_OP_FLAGS;
+#if defined(CONFIG_USER_ONLY)
+#ifdef TARGET_SPARC64
+ env->cleanwin = env->nwindows - 2;
+ env->cansave = env->nwindows - 2;
+ env->pstate = PS_RMO | PS_PEF | PS_IE;
+ env->asi = 0x82; /* Primary no-fault */
+#endif
+#else
+#if !defined(TARGET_SPARC64)
+ env->psret = 0;
+ env->psrs = 1;
+ env->psrps = 1;
+#endif
+#ifdef TARGET_SPARC64
+ env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
+ env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
+ env->tl = env->maxtl;
+ cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
+ env->lsu = 0;
+#else
+ env->mmuregs[0] &= ~(MMU_E | MMU_NF);
+ env->mmuregs[0] |= env->def->mmu_bm;
+#endif
+ env->pc = 0;
+ env->npc = env->pc + 4;
+#endif
+ env->cache_control = 0;
+}
+
+static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
+{
+ sparc_def_t def1, *def = &def1;
+
+ if (cpu_sparc_find_by_name(def, cpu_model) < 0) {
+ return -1;
+ }
+
+ env->def = g_new0(sparc_def_t, 1);
+ memcpy(env->def, def, sizeof(*def));
+#if defined(CONFIG_USER_ONLY)
+ if ((env->def->features & CPU_FEATURE_FLOAT)) {
+ env->def->features |= CPU_FEATURE_FLOAT128;
+ }
+#endif
+ env->cpu_model_str = cpu_model;
+ env->version = def->iu_version;
+ env->fsr = def->fpu_version;
+ env->nwindows = def->nwindows;
+#if !defined(TARGET_SPARC64)
+ env->mmuregs[0] |= def->mmu_version;
+ cpu_sparc_set_id(env, 0);
+ env->mxccregs[7] |= def->mxcc_version;
+#else
+ env->mmu_version = def->mmu_version;
+ env->maxtl = def->maxtl;
+ env->version |= def->maxtl << 8;
+ env->version |= def->nwindows - 1;
+#endif
+ return 0;
+}
+
+static void cpu_sparc_close(CPUSPARCState *env)
+{
+ g_free(env->def);
+ g_free(env);
+}
+
+CPUSPARCState *cpu_sparc_init(const char *cpu_model)
+{
+ CPUSPARCState *env;
+
+ env = g_new0(CPUSPARCState, 1);
+ cpu_exec_init(env);
+
+ gen_intermediate_code_init(env);
+
+ if (cpu_sparc_register(env, cpu_model) < 0) {
+ cpu_sparc_close(env);
+ return NULL;
+ }
+ qemu_init_vcpu(env);
+
+ return env;
+}
+
+void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+{
+#if !defined(TARGET_SPARC64)
+ env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
+#endif
+}
+
+static const sparc_def_t sparc_defs[] = {
+#ifdef TARGET_SPARC64
+ {
+ .name = "Fujitsu Sparc64",
+ .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 4,
+ .maxtl = 4,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 III",
+ .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 5,
+ .maxtl = 4,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 IV",
+ .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 V",
+ .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc I",
+ .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc II",
+ .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc IIi",
+ .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc IIe",
+ .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc III",
+ .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc III Cu",
+ .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_3,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IIIi",
+ .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IV",
+ .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_4,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IV+",
+ .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
+ },
+ {
+ .name = "Sun UltraSparc IIIi+",
+ .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_3,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc T1",
+ /* defined in sparc_ifu_fdp.v and ctu.h */
+ .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_sun4v,
+ .nwindows = 8,
+ .maxtl = 6,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+ | CPU_FEATURE_GL,
+ },
+ {
+ .name = "Sun UltraSparc T2",
+ /* defined in tlu_asi_ctl.v and n2_revid_cust.v */
+ .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_sun4v,
+ .nwindows = 8,
+ .maxtl = 6,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+ | CPU_FEATURE_GL,
+ },
+ {
+ .name = "NEC UltraSparc I",
+ .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+#else
+ {
+ .name = "Fujitsu MB86900",
+ .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 7,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Fujitsu MB86904",
+ .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu MB86907",
+ .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "LSI L64811",
+ .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
+ .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Cypress CY7C601",
+ .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Cypress CY7C611",
+ .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "TI MicroSparc I",
+ .iu_version = 0x41000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x41000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x0000003f,
+ .nwindows = 7,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
+ CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FMUL,
+ },
+ {
+ .name = "TI MicroSparc II",
+ .iu_version = 0x42000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x02000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI MicroSparc IIep",
+ .iu_version = 0x42000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x04000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016bff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 40", /* STP1020NPGA */
+ .iu_version = 0x41000000, /* SuperSPARC 2.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 50", /* STP1020PGA */
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 51",
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 60", /* STP1020APGA */
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 61",
+ .iu_version = 0x44000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc II",
+ .iu_version = 0x40000000, /* SuperSPARC II 1.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Ross RT625",
+ .iu_version = 0x1e000000,
+ .fpu_version = 1 << 17,
+ .mmu_version = 0x1e000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Ross RT620",
+ .iu_version = 0x1f000000,
+ .fpu_version = 1 << 17,
+ .mmu_version = 0x1f000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "BIT B5010",
+ .iu_version = 0x20000000,
+ .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
+ .mmu_version = 0x20000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Matsushita MN10501",
+ .iu_version = 0x50000000,
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x50000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Weitek W8601",
+ .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "LEON2",
+ .iu_version = 0xf2000000,
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0xf2000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
+ },
+ {
+ .name = "LEON3",
+ .iu_version = 0xf3000000,
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0xf3000000,
+ .mmu_bm = 0x00000000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
+ CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
+ },
+#endif
+};
+
+static const char * const feature_name[] = {
+ "float",
+ "float128",
+ "swap",
+ "mul",
+ "div",
+ "flush",
+ "fsqrt",
+ "fmul",
+ "vis1",
+ "vis2",
+ "fsmuld",
+ "hypv",
+ "cmt",
+ "gl",
+};
+
+static void print_features(FILE *f, fprintf_function cpu_fprintf,
+ uint32_t features, const char *prefix)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+ if (feature_name[i] && (features & (1 << i))) {
+ if (prefix) {
+ (*cpu_fprintf)(f, "%s", prefix);
+ }
+ (*cpu_fprintf)(f, "%s ", feature_name[i]);
+ }
+ }
+}
+
+static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+ if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
+ *features |= 1 << i;
+ return;
+ }
+ }
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
+{
+ unsigned int i;
+ const sparc_def_t *def = NULL;
+ char *s = strdup(cpu_model);
+ char *featurestr, *name = strtok(s, ",");
+ uint32_t plus_features = 0;
+ uint32_t minus_features = 0;
+ uint64_t iu_version;
+ uint32_t fpu_version, mmu_version, nwindows;
+
+ for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+ if (strcasecmp(name, sparc_defs[i].name) == 0) {
+ def = &sparc_defs[i];
+ }
+ }
+ if (!def) {
+ goto error;
+ }
+ memcpy(cpu_def, def, sizeof(*def));
+
+ featurestr = strtok(NULL, ",");
+ while (featurestr) {
+ char *val;
+
+ if (featurestr[0] == '+') {
+ add_flagname_to_bitmaps(featurestr + 1, &plus_features);
+ } else if (featurestr[0] == '-') {
+ add_flagname_to_bitmaps(featurestr + 1, &minus_features);
+ } else if ((val = strchr(featurestr, '='))) {
+ *val = 0; val++;
+ if (!strcmp(featurestr, "iu_version")) {
+ char *err;
+
+ iu_version = strtoll(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->iu_version = iu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
+#endif
+ } else if (!strcmp(featurestr, "fpu_version")) {
+ char *err;
+
+ fpu_version = strtol(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->fpu_version = fpu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "fpu_version %x\n", fpu_version);
+#endif
+ } else if (!strcmp(featurestr, "mmu_version")) {
+ char *err;
+
+ mmu_version = strtol(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->mmu_version = mmu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "mmu_version %x\n", mmu_version);
+#endif
+ } else if (!strcmp(featurestr, "nwindows")) {
+ char *err;
+
+ nwindows = strtol(val, &err, 0);
+ if (!*val || *err || nwindows > MAX_NWINDOWS ||
+ nwindows < MIN_NWINDOWS) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->nwindows = nwindows;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "nwindows %d\n", nwindows);
+#endif
+ } else {
+ fprintf(stderr, "unrecognized feature %s\n", featurestr);
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "feature string `%s' not in format "
+ "(+feature|-feature|feature=xyz)\n", featurestr);
+ goto error;
+ }
+ featurestr = strtok(NULL, ",");
+ }
+ cpu_def->features |= plus_features;
+ cpu_def->features &= ~minus_features;
+#ifdef DEBUG_FEATURES
+ print_features(stderr, fprintf, cpu_def->features, NULL);
+#endif
+ free(s);
+ return 0;
+
+ error:
+ free(s);
+ return -1;
+}
+
+void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+ (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx
+ " FPU %08x MMU %08x NWINS %d ",
+ sparc_defs[i].name,
+ sparc_defs[i].iu_version,
+ sparc_defs[i].fpu_version,
+ sparc_defs[i].mmu_version,
+ sparc_defs[i].nwindows);
+ print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
+ ~sparc_defs[i].features, "-");
+ print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
+ sparc_defs[i].features, "+");
+ (*cpu_fprintf)(f, "\n");
+ }
+ (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
+ print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
+ (*cpu_fprintf)(f, "\n");
+ (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
+ print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
+ (*cpu_fprintf)(f, "\n");
+ (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
+ "fpu_version mmu_version nwindows\n");
+}
+
+static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
+ uint32_t cc)
+{
+ cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-',
+ cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-',
+ cc & PSR_CARRY ? 'C' : '-');
+}
+
+#ifdef TARGET_SPARC64
+#define REGS_PER_LINE 4
+#else
+#define REGS_PER_LINE 8
+#endif
+
+void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf,
+ int flags)
+{
+ int i, x;
+
+ cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
+ env->npc);
+ cpu_fprintf(f, "General Registers:\n");
+
+ for (i = 0; i < 8; i++) {
+ if (i % REGS_PER_LINE == 0) {
+ cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
+ }
+ cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
+ if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+ cpu_fprintf(f, "\nCurrent Register Window:\n");
+ for (x = 0; x < 3; x++) {
+ for (i = 0; i < 8; i++) {
+ if (i % REGS_PER_LINE == 0) {
+ cpu_fprintf(f, "%%%c%d-%d: ",
+ x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
+ i, i + REGS_PER_LINE - 1);
+ }
+ cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
+ if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+ }
+ cpu_fprintf(f, "\nFloating Point Registers:\n");
+ for (i = 0; i < TARGET_DPREGS; i++) {
+ if ((i & 3) == 0) {
+ cpu_fprintf(f, "%%f%02d:", i * 2);
+ }
+ cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll);
+ if ((i & 3) == 3) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+#ifdef TARGET_SPARC64
+ cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
+ (unsigned)cpu_get_ccr(env));
+ cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
+ cpu_fprintf(f, " xcc: ");
+ cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
+ cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
+ env->psrpil);
+ cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
+ "cleanwin: %d cwp: %d\n",
+ env->cansave, env->canrestore, env->otherwin, env->wstate,
+ env->cleanwin, env->nwindows - 1 - env->cwp);
+ cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
+ TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
+#else
+ cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
+ cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
+ cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-',
+ env->psrps ? 'P' : '-', env->psret ? 'E' : '-',
+ env->wim);
+ cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
+ env->fsr, env->y);
+#endif
+}
diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c
deleted file mode 100644
index 5c03f0b..0000000
--- a/target-sparc/cpu_init.c
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * Sparc CPU init helpers
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "cpu.h"
-
-//#define DEBUG_FEATURES
-
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
-
-void cpu_state_reset(CPUSPARCState *env)
-{
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- memset(env, 0, offsetof(CPUSPARCState, breakpoints));
- tlb_flush(env, 1);
- env->cwp = 0;
-#ifndef TARGET_SPARC64
- env->wim = 1;
-#endif
- env->regwptr = env->regbase + (env->cwp * 16);
- CC_OP = CC_OP_FLAGS;
-#if defined(CONFIG_USER_ONLY)
-#ifdef TARGET_SPARC64
- env->cleanwin = env->nwindows - 2;
- env->cansave = env->nwindows - 2;
- env->pstate = PS_RMO | PS_PEF | PS_IE;
- env->asi = 0x82; /* Primary no-fault */
-#endif
-#else
-#if !defined(TARGET_SPARC64)
- env->psret = 0;
- env->psrs = 1;
- env->psrps = 1;
-#endif
-#ifdef TARGET_SPARC64
- env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
- env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
- env->tl = env->maxtl;
- cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
- env->lsu = 0;
-#else
- env->mmuregs[0] &= ~(MMU_E | MMU_NF);
- env->mmuregs[0] |= env->def->mmu_bm;
-#endif
- env->pc = 0;
- env->npc = env->pc + 4;
-#endif
- env->cache_control = 0;
-}
-
-static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
-{
- sparc_def_t def1, *def = &def1;
-
- if (cpu_sparc_find_by_name(def, cpu_model) < 0) {
- return -1;
- }
-
- env->def = g_new0(sparc_def_t, 1);
- memcpy(env->def, def, sizeof(*def));
-#if defined(CONFIG_USER_ONLY)
- if ((env->def->features & CPU_FEATURE_FLOAT)) {
- env->def->features |= CPU_FEATURE_FLOAT128;
- }
-#endif
- env->cpu_model_str = cpu_model;
- env->version = def->iu_version;
- env->fsr = def->fpu_version;
- env->nwindows = def->nwindows;
-#if !defined(TARGET_SPARC64)
- env->mmuregs[0] |= def->mmu_version;
- cpu_sparc_set_id(env, 0);
- env->mxccregs[7] |= def->mxcc_version;
-#else
- env->mmu_version = def->mmu_version;
- env->maxtl = def->maxtl;
- env->version |= def->maxtl << 8;
- env->version |= def->nwindows - 1;
-#endif
- return 0;
-}
-
-static void cpu_sparc_close(CPUSPARCState *env)
-{
- g_free(env->def);
- g_free(env);
-}
-
-CPUSPARCState *cpu_sparc_init(const char *cpu_model)
-{
- CPUSPARCState *env;
-
- env = g_new0(CPUSPARCState, 1);
- cpu_exec_init(env);
-
- gen_intermediate_code_init(env);
-
- if (cpu_sparc_register(env, cpu_model) < 0) {
- cpu_sparc_close(env);
- return NULL;
- }
- qemu_init_vcpu(env);
-
- return env;
-}
-
-void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
-{
-#if !defined(TARGET_SPARC64)
- env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
-#endif
-}
-
-static const sparc_def_t sparc_defs[] = {
-#ifdef TARGET_SPARC64
- {
- .name = "Fujitsu Sparc64",
- .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 4,
- .maxtl = 4,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 III",
- .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 5,
- .maxtl = 4,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 IV",
- .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 V",
- .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc I",
- .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc II",
- .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc IIi",
- .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc IIe",
- .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc III",
- .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc III Cu",
- .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_3,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IIIi",
- .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IV",
- .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_4,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IV+",
- .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
- },
- {
- .name = "Sun UltraSparc IIIi+",
- .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_3,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc T1",
- /* defined in sparc_ifu_fdp.v and ctu.h */
- .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_sun4v,
- .nwindows = 8,
- .maxtl = 6,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
- | CPU_FEATURE_GL,
- },
- {
- .name = "Sun UltraSparc T2",
- /* defined in tlu_asi_ctl.v and n2_revid_cust.v */
- .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_sun4v,
- .nwindows = 8,
- .maxtl = 6,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
- | CPU_FEATURE_GL,
- },
- {
- .name = "NEC UltraSparc I",
- .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
-#else
- {
- .name = "Fujitsu MB86900",
- .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 7,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
- },
- {
- .name = "Fujitsu MB86904",
- .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu MB86907",
- .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "LSI L64811",
- .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
- .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Cypress CY7C601",
- .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
- .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Cypress CY7C611",
- .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
- .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "TI MicroSparc I",
- .iu_version = 0x41000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x41000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x0000003f,
- .nwindows = 7,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
- CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FMUL,
- },
- {
- .name = "TI MicroSparc II",
- .iu_version = 0x42000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x02000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI MicroSparc IIep",
- .iu_version = 0x42000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x04000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016bff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 40", /* STP1020NPGA */
- .iu_version = 0x41000000, /* SuperSPARC 2.x */
- .fpu_version = 0 << 17,
- .mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 50", /* STP1020PGA */
- .iu_version = 0x40000000, /* SuperSPARC 3.x */
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 51",
- .iu_version = 0x40000000, /* SuperSPARC 3.x */
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 60", /* STP1020APGA */
- .iu_version = 0x40000000, /* SuperSPARC 3.x */
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 61",
- .iu_version = 0x44000000, /* SuperSPARC 3.x */
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc II",
- .iu_version = 0x40000000, /* SuperSPARC II 1.x */
- .fpu_version = 0 << 17,
- .mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Ross RT625",
- .iu_version = 0x1e000000,
- .fpu_version = 1 << 17,
- .mmu_version = 0x1e000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Ross RT620",
- .iu_version = 0x1f000000,
- .fpu_version = 1 << 17,
- .mmu_version = 0x1f000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "BIT B5010",
- .iu_version = 0x20000000,
- .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
- .mmu_version = 0x20000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Matsushita MN10501",
- .iu_version = 0x50000000,
- .fpu_version = 0 << 17,
- .mmu_version = 0x50000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Weitek W8601",
- .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
- .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "LEON2",
- .iu_version = 0xf2000000,
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0xf2000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
- },
- {
- .name = "LEON3",
- .iu_version = 0xf3000000,
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0xf3000000,
- .mmu_bm = 0x00000000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
- CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
- },
-#endif
-};
-
-static const char * const feature_name[] = {
- "float",
- "float128",
- "swap",
- "mul",
- "div",
- "flush",
- "fsqrt",
- "fmul",
- "vis1",
- "vis2",
- "fsmuld",
- "hypv",
- "cmt",
- "gl",
-};
-
-static void print_features(FILE *f, fprintf_function cpu_fprintf,
- uint32_t features, const char *prefix)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
- if (feature_name[i] && (features & (1 << i))) {
- if (prefix) {
- (*cpu_fprintf)(f, "%s", prefix);
- }
- (*cpu_fprintf)(f, "%s ", feature_name[i]);
- }
- }
-}
-
-static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
- if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
- *features |= 1 << i;
- return;
- }
- }
- fprintf(stderr, "CPU feature %s not found\n", flagname);
-}
-
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
-{
- unsigned int i;
- const sparc_def_t *def = NULL;
- char *s = strdup(cpu_model);
- char *featurestr, *name = strtok(s, ",");
- uint32_t plus_features = 0;
- uint32_t minus_features = 0;
- uint64_t iu_version;
- uint32_t fpu_version, mmu_version, nwindows;
-
- for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
- if (strcasecmp(name, sparc_defs[i].name) == 0) {
- def = &sparc_defs[i];
- }
- }
- if (!def) {
- goto error;
- }
- memcpy(cpu_def, def, sizeof(*def));
-
- featurestr = strtok(NULL, ",");
- while (featurestr) {
- char *val;
-
- if (featurestr[0] == '+') {
- add_flagname_to_bitmaps(featurestr + 1, &plus_features);
- } else if (featurestr[0] == '-') {
- add_flagname_to_bitmaps(featurestr + 1, &minus_features);
- } else if ((val = strchr(featurestr, '='))) {
- *val = 0; val++;
- if (!strcmp(featurestr, "iu_version")) {
- char *err;
-
- iu_version = strtoll(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->iu_version = iu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
-#endif
- } else if (!strcmp(featurestr, "fpu_version")) {
- char *err;
-
- fpu_version = strtol(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->fpu_version = fpu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "fpu_version %x\n", fpu_version);
-#endif
- } else if (!strcmp(featurestr, "mmu_version")) {
- char *err;
-
- mmu_version = strtol(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->mmu_version = mmu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "mmu_version %x\n", mmu_version);
-#endif
- } else if (!strcmp(featurestr, "nwindows")) {
- char *err;
-
- nwindows = strtol(val, &err, 0);
- if (!*val || *err || nwindows > MAX_NWINDOWS ||
- nwindows < MIN_NWINDOWS) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->nwindows = nwindows;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "nwindows %d\n", nwindows);
-#endif
- } else {
- fprintf(stderr, "unrecognized feature %s\n", featurestr);
- goto error;
- }
- } else {
- fprintf(stderr, "feature string `%s' not in format "
- "(+feature|-feature|feature=xyz)\n", featurestr);
- goto error;
- }
- featurestr = strtok(NULL, ",");
- }
- cpu_def->features |= plus_features;
- cpu_def->features &= ~minus_features;
-#ifdef DEBUG_FEATURES
- print_features(stderr, fprintf, cpu_def->features, NULL);
-#endif
- free(s);
- return 0;
-
- error:
- free(s);
- return -1;
-}
-
-void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
- (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx
- " FPU %08x MMU %08x NWINS %d ",
- sparc_defs[i].name,
- sparc_defs[i].iu_version,
- sparc_defs[i].fpu_version,
- sparc_defs[i].mmu_version,
- sparc_defs[i].nwindows);
- print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
- ~sparc_defs[i].features, "-");
- print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
- sparc_defs[i].features, "+");
- (*cpu_fprintf)(f, "\n");
- }
- (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
- print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
- (*cpu_fprintf)(f, "\n");
- (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
- print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
- (*cpu_fprintf)(f, "\n");
- (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
- "fpu_version mmu_version nwindows\n");
-}
-
-static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
- uint32_t cc)
-{
- cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-',
- cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-',
- cc & PSR_CARRY ? 'C' : '-');
-}
-
-#ifdef TARGET_SPARC64
-#define REGS_PER_LINE 4
-#else
-#define REGS_PER_LINE 8
-#endif
-
-void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf,
- int flags)
-{
- int i, x;
-
- cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
- env->npc);
- cpu_fprintf(f, "General Registers:\n");
-
- for (i = 0; i < 8; i++) {
- if (i % REGS_PER_LINE == 0) {
- cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
- }
- cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
- if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
- cpu_fprintf(f, "\n");
- }
- }
- cpu_fprintf(f, "\nCurrent Register Window:\n");
- for (x = 0; x < 3; x++) {
- for (i = 0; i < 8; i++) {
- if (i % REGS_PER_LINE == 0) {
- cpu_fprintf(f, "%%%c%d-%d: ",
- x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
- i, i + REGS_PER_LINE - 1);
- }
- cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
- if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
- cpu_fprintf(f, "\n");
- }
- }
- }
- cpu_fprintf(f, "\nFloating Point Registers:\n");
- for (i = 0; i < TARGET_DPREGS; i++) {
- if ((i & 3) == 0) {
- cpu_fprintf(f, "%%f%02d:", i * 2);
- }
- cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll);
- if ((i & 3) == 3) {
- cpu_fprintf(f, "\n");
- }
- }
-#ifdef TARGET_SPARC64
- cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
- (unsigned)cpu_get_ccr(env));
- cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
- cpu_fprintf(f, " xcc: ");
- cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
- cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
- env->psrpil);
- cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
- "cleanwin: %d cwp: %d\n",
- env->cansave, env->canrestore, env->otherwin, env->wstate,
- env->cleanwin, env->nwindows - 1 - env->cwp);
- cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
- TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
-#else
- cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
- cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
- cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-',
- env->psrps ? 'P' : '-', env->psret ? 'E' : '-',
- env->wim);
- cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
- env->fsr, env->y);
-#endif
-}
commit d8fd2954996255ba6ad610917e7849832d0120b7
Author: Paul Brook <paul at codesourcery.com>
Date: Fri Mar 30 18:02:50 2012 +0100
Userspace ARM BE8 support
Add support for ARM BE8 userspace binaries.
i.e. big-endian data and little-endian code.
In principle LE8 mode is also possible, but AFAIK has never actually
been implemented/used.
System emulation doesn't have any useable big-endian board models,
but should in principle work once you fix that.
Dynamic endianness switching requires messing with data accesses,
preferably with TCG cooperation, and is orthogonal to BE8 support.
Signed-off-by: Paul Brook <paul at codesourcery.com>
[PMM: various changes, mostly as per my suggestions in code review:
* rebase
* use EF_ defines rather than hardcoded constants
* make bswap_code a bool for future VMSTATE macro compatibility
* update comment in cpu.h about TB flags bit field usage
* factor out load-code-and-swap into arm_ld*_code functions and
get_user_code* macros
* fix stray trailing space at end of line
* added braces in disas.c to satisfy checkpatch
]
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/disas.c b/disas.c
index 9485824..4f2c4e4 100644
--- a/disas.c
+++ b/disas.c
@@ -138,7 +138,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
/* Disassemble this for me please... (debugging). 'flags' has the following
values:
i386 - 1 means 16 bit code, 2 means 64 bit code
- arm - nonzero means thumb code
+ arm - bit 0 = thumb, bit 1 = reverse endian
ppc - nonzero means little endian
other targets - unused
*/
@@ -169,10 +169,18 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
- if (flags)
- print_insn = print_insn_thumb1;
- else
- print_insn = print_insn_arm;
+ if (flags & 1) {
+ print_insn = print_insn_thumb1;
+ } else {
+ print_insn = print_insn_arm;
+ }
+ if (flags & 2) {
+#ifdef TARGET_WORDS_BIGENDIAN
+ disasm_info.endian = BFD_ENDIAN_LITTLE;
+#else
+ disasm_info.endian = BFD_ENDIAN_BIG;
+#endif
+ }
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#ifdef TARGET_SPARC64
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 4ce9743..f3b1552 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1576,6 +1576,7 @@ static void load_elf_image(const char *image_name, int image_fd,
info->start_data = -1;
info->end_data = 0;
info->brk = 0;
+ info->elf_flags = ehdr->e_flags;
for (i = 0; i < ehdr->e_phnum; i++) {
struct elf_phdr *eppnt = phdr + i;
diff --git a/linux-user/main.c b/linux-user/main.c
index 23ad357..191b750 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -33,6 +33,7 @@
#include "tcg.h"
#include "qemu-timer.h"
#include "envlist.h"
+#include "elf.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
@@ -474,6 +475,22 @@ void cpu_loop(CPUX86State *env)
#ifdef TARGET_ARM
+#define get_user_code_u32(x, gaddr, doswap) \
+ ({ abi_long __r = get_user_u32((x), (gaddr)); \
+ if (!__r && (doswap)) { \
+ (x) = bswap32(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_code_u16(x, gaddr, doswap) \
+ ({ abi_long __r = get_user_u16((x), (gaddr)); \
+ if (!__r && (doswap)) { \
+ (x) = bswap16(x); \
+ } \
+ __r; \
+ })
+
/*
* See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
* Input:
@@ -707,7 +724,7 @@ void cpu_loop(CPUARMState *env)
/* we handle the FPU emulation here, as Linux */
/* we get the opcode */
/* FIXME - what to do if get_user() fails? */
- get_user_u32(opcode, env->regs[15]);
+ get_user_code_u32(opcode, env->regs[15], env->bswap_code);
rc = EmulateAll(opcode, &ts->fpa, env);
if (rc == 0) { /* illegal instruction */
@@ -777,23 +794,25 @@ void cpu_loop(CPUARMState *env)
if (trapnr == EXCP_BKPT) {
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
- get_user_u16(insn, env->regs[15]);
+ get_user_code_u16(insn, env->regs[15], env->bswap_code);
n = insn & 0xff;
env->regs[15] += 2;
} else {
/* FIXME - what to do if get_user() fails? */
- get_user_u32(insn, env->regs[15]);
+ get_user_code_u32(insn, env->regs[15], env->bswap_code);
n = (insn & 0xf) | ((insn >> 4) & 0xff0);
env->regs[15] += 4;
}
} else {
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
- get_user_u16(insn, env->regs[15] - 2);
+ get_user_code_u16(insn, env->regs[15] - 2,
+ env->bswap_code);
n = insn & 0xff;
} else {
/* FIXME - what to do if get_user() fails? */
- get_user_u32(insn, env->regs[15] - 4);
+ get_user_code_u32(insn, env->regs[15] - 4,
+ env->bswap_code);
n = insn & 0xffffff;
}
}
@@ -3657,6 +3676,11 @@ int main(int argc, char **argv, char **envp)
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
}
+ /* Enable BE8. */
+ if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
+ && (info->elf_flags & EF_ARM_BE8)) {
+ env->bswap_code = 1;
+ }
}
#elif defined(TARGET_UNICORE32)
{
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index dd74cc0..7b299b7 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -51,6 +51,7 @@ struct image_info {
abi_ulong auxv_len;
abi_ulong arg_start;
abi_ulong arg_end;
+ uint32_t elf_flags;
int personality;
#ifdef CONFIG_USE_FDPIC
abi_ulong loadmap_addr;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index e176c5f..c208c80 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -216,6 +216,9 @@ typedef struct CPUARMState {
uint32_t cregs[16];
} iwmmxt;
+ /* For mixed endian mode. */
+ bool bswap_code;
+
#if defined(CONFIG_USER_ONLY)
/* For usermode syscall translation. */
int eabi;
@@ -491,7 +494,9 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
#define ARM_TBFLAG_VFPEN_MASK (1 << ARM_TBFLAG_VFPEN_SHIFT)
#define ARM_TBFLAG_CONDEXEC_SHIFT 8
#define ARM_TBFLAG_CONDEXEC_MASK (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
-/* Bits 31..16 are currently unused. */
+#define ARM_TBFLAG_BSWAP_CODE_SHIFT 16
+#define ARM_TBFLAG_BSWAP_CODE_MASK (1 << ARM_TBFLAG_BSWAP_CODE_SHIFT)
+/* Bits 31..17 are currently unused. */
/* some convenience accessor macros */
#define ARM_TBFLAG_THUMB(F) \
@@ -506,6 +511,8 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
(((F) & ARM_TBFLAG_VFPEN_MASK) >> ARM_TBFLAG_VFPEN_SHIFT)
#define ARM_TBFLAG_CONDEXEC(F) \
(((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
+#define ARM_TBFLAG_BSWAP_CODE(F) \
+ (((F) & ARM_TBFLAG_BSWAP_CODE_MASK) >> ARM_TBFLAG_BSWAP_CODE_SHIFT)
static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
@@ -516,7 +523,8 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
*flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
| (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
| (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
- | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT);
+ | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
+ | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
if (arm_feature(env, ARM_FEATURE_M)) {
privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
} else {
@@ -543,4 +551,24 @@ static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb)
env->regs[15] = tb->pc;
}
+/* Load an instruction and return it in the standard little-endian order */
+static inline uint32_t arm_ldl_code(uint32_t addr, bool do_swap)
+{
+ uint32_t insn = ldl_code(addr);
+ if (do_swap) {
+ return bswap32(insn);
+ }
+ return insn;
+}
+
+/* Ditto, for a halfword (Thumb) instruction */
+static inline uint16_t arm_lduw_code(uint32_t addr, bool do_swap)
+{
+ uint16_t insn = lduw_code(addr);
+ if (do_swap) {
+ return bswap16(insn);
+ }
+ return insn;
+}
+
#endif
diff --git a/target-arm/helper.c b/target-arm/helper.c
index d974b57..28f127b 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -842,7 +842,7 @@ static void do_interrupt_v7m(CPUARMState *env)
case EXCP_BKPT:
if (semihosting_enabled) {
int nr;
- nr = lduw_code(env->regs[15]) & 0xff;
+ nr = arm_lduw_code(env->regs[15], env->bswap_code) & 0xff;
if (nr == 0xab) {
env->regs[15] += 2;
env->regs[0] = do_arm_semihosting(env);
@@ -914,9 +914,10 @@ void do_interrupt(CPUARMState *env)
if (semihosting_enabled) {
/* Check for semihosting interrupt. */
if (env->thumb) {
- mask = lduw_code(env->regs[15] - 2) & 0xff;
+ mask = arm_lduw_code(env->regs[15] - 2, env->bswap_code) & 0xff;
} else {
- mask = ldl_code(env->regs[15] - 4) & 0xffffff;
+ mask = arm_ldl_code(env->regs[15] - 4, env->bswap_code)
+ & 0xffffff;
}
/* Only intercept calls from privileged modes, to provide some
semblance of security. */
@@ -936,7 +937,7 @@ void do_interrupt(CPUARMState *env)
case EXCP_BKPT:
/* See if this is a semihosting syscall. */
if (env->thumb && semihosting_enabled) {
- mask = lduw_code(env->regs[15]) & 0xff;
+ mask = arm_lduw_code(env->regs[15], env->bswap_code) & 0xff;
if (mask == 0xab
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
env->regs[15] += 2;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 46d1d3e..7a3c7d6 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -59,6 +59,7 @@ typedef struct DisasContext {
struct TranslationBlock *tb;
int singlestep_enabled;
int thumb;
+ int bswap_code;
#if !defined(CONFIG_USER_ONLY)
int user;
#endif
@@ -6705,7 +6706,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
TCGv addr;
TCGv_i64 tmp64;
- insn = ldl_code(s->pc);
+ insn = arm_ldl_code(s->pc, s->bswap_code);
s->pc += 4;
/* M variants do not implement ARM mode. */
@@ -8133,7 +8134,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
/* Fall through to 32-bit decode. */
}
- insn = lduw_code(s->pc);
+ insn = arm_lduw_code(s->pc, s->bswap_code);
s->pc += 2;
insn |= (uint32_t)insn_hw1 << 16;
@@ -9163,7 +9164,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
}
}
- insn = lduw_code(s->pc);
+ insn = arm_lduw_code(s->pc, s->bswap_code);
s->pc += 2;
switch (insn >> 12) {
@@ -9872,6 +9873,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
dc->singlestep_enabled = env->singlestep_enabled;
dc->condjmp = 0;
dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
+ dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
#if !defined(CONFIG_USER_ONLY)
@@ -10105,7 +10107,8 @@ done_generating:
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("----------------\n");
qemu_log("IN: %s\n", lookup_symbol(pc_start));
- log_target_disas(pc_start, dc->pc - pc_start, dc->thumb);
+ log_target_disas(pc_start, dc->pc - pc_start,
+ dc->thumb | (dc->bswap_code << 1));
qemu_log("\n");
}
#endif
commit ef8b0c0474aa7eab5172e866dc37428b41ff2934
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Mar 30 18:02:49 2012 +0100
elf.h: Update EF_ARM_ constants to newer ABI versions
Update the EF_ARM_* constants (for the ELF header e_flags field)
to include the newer flags specified for later versions of the ABI.
(This set of constants is from include/elf/arm.h from binutils-2.17
and so licensed under GPL-v2-or-later.)
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/elf.h b/elf.h
index 36bcac4..e1422b8 100644
--- a/elf.h
+++ b/elf.h
@@ -538,6 +538,27 @@ typedef struct {
#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */
#define EF_NEW_ABI 0x80
#define EF_OLD_ABI 0x100
+#define EF_ARM_SOFT_FLOAT 0x200
+#define EF_ARM_VFP_FLOAT 0x400
+#define EF_ARM_MAVERICK_FLOAT 0x800
+
+/* Other constants defined in the ARM ELF spec. version B-01. */
+#define EF_ARM_SYMSARESORTED 0x04 /* NB conflicts with EF_INTERWORK */
+#define EF_ARM_DYNSYMSUSESEGIDX 0x08 /* NB conflicts with EF_APCS26 */
+#define EF_ARM_MAPSYMSFIRST 0x10 /* NB conflicts with EF_APCS_FLOAT */
+#define EF_ARM_EABIMASK 0xFF000000
+
+/* Constants defined in AAELF. */
+#define EF_ARM_BE8 0x00800000
+#define EF_ARM_LE8 0x00400000
+
+#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN 0x00000000
+#define EF_ARM_EABI_VER1 0x01000000
+#define EF_ARM_EABI_VER2 0x02000000
+#define EF_ARM_EABI_VER3 0x03000000
+#define EF_ARM_EABI_VER4 0x04000000
+#define EF_ARM_EABI_VER5 0x05000000
/* Additional symbol types for Thumb */
#define STT_ARM_TFUNC 0xd
commit adf050b1b9f0fe7f921780eeb1888ce53d94d10b
Author: Benoit Canet <benoit.canet at gmail.com>
Date: Wed Nov 9 03:37:23 2011 +0000
arm-linux-user: fix elfload.c's AT_HWCAP to reflect cpu features.
The cpu capabilities passed by the elf loader in AT_HWCAP where
a constant.
Make AT_HWCAP reflect the emulated cpu features in order to give
correct clues to eglibc.
Riku Voipio: fixed to apply to current head
Fix : [Bug 887516] [NEW] VFP support reported for the PXA270
Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index e502b39..4ce9743 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -375,10 +375,33 @@ bool guest_validate_base(unsigned long guest_base)
return 1; /* All good */
}
-#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \
- | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \
- | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP \
- | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+ CPUARMState *e = thread_env;
+ uint32_t hwcaps = 0;
+
+ hwcaps |= ARM_HWCAP_ARM_SWP;
+ hwcaps |= ARM_HWCAP_ARM_HALF;
+ hwcaps |= ARM_HWCAP_ARM_THUMB;
+ hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
+ hwcaps |= ARM_HWCAP_ARM_FPA;
+
+ /* probe for the extra features */
+#define GET_FEATURE(feat, hwcap) \
+ do {if (arm_feature(e, feat)) { hwcaps |= hwcap; } } while (0)
+ GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP);
+ GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
+ GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
+ GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
+ GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3);
+ GET_FEATURE(ARM_FEATURE_VFP_FP16, ARM_HWCAP_ARM_VFPv3D16);
+#undef GET_FEATURE
+
+ return hwcaps;
+}
#endif
commit d1b02ea0dcd20998ef178ddc55fb9765f6aa1d44
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Mar 16 17:16:36 2012 +0000
linux-user/arm/syscall_nr.h: Add syscall number for ppoll
The list of ARM syscall numbers was missing the entry for ppoll,
which meant we were accidentally not providing it. (This wasn't
causing any practical issues beyond warnings about unimplemented
syscalls, because glibc will fall back to another code path if the
syscall isn't present.)
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h
index 7f05879..5356395 100644
--- a/linux-user/arm/syscall_nr.h
+++ b/linux-user/arm/syscall_nr.h
@@ -339,7 +339,7 @@
#define TARGET_NR_fchmodat (333)
#define TARGET_NR_faccessat (334)
#define TARGET_NR_pselect6 (335)
- /* 336 for ppoll */
+#define TARGET_NR_ppoll (336)
#define TARGET_NR_unshare (337)
#define TARGET_NR_set_robust_list (338)
#define TARGET_NR_get_robust_list (339)
commit db9526b10a956fd80c08727685c300b63d5a7465
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Feb 3 14:48:03 2012 +0000
linux-user: Add support for prctl PR_GET_NAME and PR_SET_NAME
Add support for the prctl options PR_GET_NAME and PR_SET_NAME,
which take or return a name in a 16 byte buffer pointed to by arg2.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ea44f99..8a92162 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7253,6 +7253,30 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
break;
}
+#ifdef PR_GET_NAME
+ case PR_GET_NAME:
+ {
+ void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
+ if (!name) {
+ goto efault;
+ }
+ ret = get_errno(prctl(arg1, (unsigned long)name,
+ arg3, arg4, arg5));
+ unlock_user(name, arg2, 16);
+ break;
+ }
+ case PR_SET_NAME:
+ {
+ void *name = lock_user(VERIFY_READ, arg2, 16, 1);
+ if (!name) {
+ goto efault;
+ }
+ ret = get_errno(prctl(arg1, (unsigned long)name,
+ arg3, arg4, arg5));
+ unlock_user(name, arg2, 0);
+ break;
+ }
+#endif
default:
/* Most prctl options have no pointer arguments */
ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
commit 1e6722f8b0c1eaff305c39d32c07054450ebdad1
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Feb 3 14:48:03 2012 +0000
linux-user/syscall.c: Fix indentation in prctl handling
Clean up the odd indentation of this switch statement before
we double its size by adding new cases to it.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index fdd49b1..ea44f99 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7242,21 +7242,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
goto unimplemented;
#endif
case TARGET_NR_prctl:
- switch (arg1)
- {
- case PR_GET_PDEATHSIG:
- {
- int deathsig;
- ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
- if (!is_error(ret) && arg2
- && put_user_ual(deathsig, arg2))
- goto efault;
- }
- break;
- default:
- ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
- break;
+ switch (arg1) {
+ case PR_GET_PDEATHSIG:
+ {
+ int deathsig;
+ ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
+ if (!is_error(ret) && arg2
+ && put_user_ual(deathsig, arg2)) {
+ goto efault;
}
+ break;
+ }
+ default:
+ /* Most prctl options have no pointer arguments */
+ ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
+ break;
+ }
break;
#ifdef TARGET_NR_arch_prctl
case TARGET_NR_arch_prctl:
commit 288e65b9eea0c9b3cbe21be46f3e24e4e8b2a090
Author: Alexander Graf <agraf at suse.de>
Date: Wed Dec 14 00:33:28 2011 +0100
linux-user: reserve 4GB of vmem for 32-on-64
When running 32-on-64 bit guests, we should always reserve as much
virtual memory as we possibly can for the guest process, so it can
never overlap with QEMU address space.
Fortunately we already have the infrastructure for that. All that's
missing is some sane default value to also make use of it!
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/main.c b/linux-user/main.c
index aa95db3..23ad357 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -48,8 +48,19 @@ unsigned long mmap_min_addr;
#if defined(CONFIG_USE_GUEST_BASE)
unsigned long guest_base;
int have_guest_base;
+#if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
+/*
+ * When running 32-on-64 we should make sure we can fit all of the possible
+ * guest address space into a contiguous chunk of virtual host memory.
+ *
+ * This way we will never overlap with our own libraries or binaries or stack
+ * or anything else that QEMU maps.
+ */
+unsigned long reserved_va = 0xf7000000;
+#else
unsigned long reserved_va;
#endif
+#endif
static void usage(void);
commit 59e9d91c7ae1b655997aec61c08eec1685414117
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Thu Mar 8 14:40:33 2012 +0000
linux-user: resolve reserved_va vma downwards
After consulting with Paul Brook, we concluded that it's best to search
the VMA space downwards, so that we don't even get the chance to conflict
with the brk range.
This patch resolves a bunch of allocation conflicts when using -R.
Signed-off-by: Alexander Graf <agraf at suse.de>
[minor changes to get it to apply -- PMM]
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/main.c b/linux-user/main.c
index 2570140..aa95db3 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3420,6 +3420,7 @@ int main(int argc, char **argv, char **envp)
guest_base = HOST_PAGE_ALIGN((unsigned long)p);
}
qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
+ mmap_next_start = reserved_va;
}
if (reserved_va || have_guest_base) {
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 994c02b..7125d1c 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -212,7 +212,7 @@ static int mmap_frag(abi_ulong real_start,
#else
# define TASK_UNMAPPED_BASE 0x40000000
#endif
-static abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
+abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
unsigned long last_brk;
@@ -222,7 +222,7 @@ unsigned long last_brk;
static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
{
abi_ulong addr;
- abi_ulong last_addr;
+ abi_ulong end_addr;
int prot;
int looped = 0;
@@ -230,25 +230,38 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
return (abi_ulong)-1;
}
- last_addr = start;
- for (addr = start; last_addr + size != addr; addr += qemu_host_page_size) {
- if (last_addr + size >= RESERVED_VA
- || (abi_ulong)(last_addr + size) < last_addr) {
+ size = HOST_PAGE_ALIGN(size);
+ end_addr = start + size;
+ if (end_addr > RESERVED_VA) {
+ end_addr = RESERVED_VA;
+ }
+ addr = end_addr - qemu_host_page_size;
+
+ while (1) {
+ if (addr > end_addr) {
if (looped) {
return (abi_ulong)-1;
}
- last_addr = qemu_host_page_size;
- addr = 0;
+ end_addr = RESERVED_VA;
+ addr = end_addr - qemu_host_page_size;
looped = 1;
continue;
}
prot = page_get_flags(addr);
if (prot) {
- last_addr = addr + qemu_host_page_size;
+ end_addr = addr;
+ }
+ if (addr + size == end_addr) {
+ break;
}
+ addr -= qemu_host_page_size;
+ }
+
+ if (start == mmap_next_start) {
+ mmap_next_start = addr;
}
- mmap_next_start = addr;
- return last_addr;
+
+ return addr;
}
#endif
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 6889567..dd74cc0 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -251,6 +251,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
abi_ulong new_addr);
int target_msync(abi_ulong start, abi_ulong len, int flags);
extern unsigned long last_brk;
+extern abi_ulong mmap_next_start;
void mmap_lock(void);
void mmap_unlock(void);
abi_ulong mmap_find_vma(abi_ulong, abi_ulong);
commit 39879bbbea4661a4004ca26673e3d1e6ae1e0bc3
Author: Alexander Graf <agraf at suse.de>
Date: Thu Feb 2 03:14:18 2012 +0100
linux-user: take RESERVED_VA into account for g2h_valid()
When running with -R (RESERVED_VA > 0) all guest virtual addresses
are within the [0..RESERVED_VA] range. Reflect this with g2h_valid()
too so we can safely check for boundaries of our guest address space.
This is required to have the /proc/self/maps code not show maps that
aren't accessible from the guest process's point of view.
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/cpu-all.h b/cpu-all.h
index 9621c3c..4512518 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -204,7 +204,8 @@ extern unsigned long reserved_va;
#else
#define h2g_valid(x) ({ \
unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \
- __guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS); \
+ (__guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS)) && \
+ (!RESERVED_VA || (__guest < RESERVED_VA)); \
})
#endif
commit 20249ae189ac0baa5011770bccabf3ee802eb2ab
Author: Alexander Graf <agraf at suse.de>
Date: Mon Feb 6 21:37:07 2012 +0100
linux-user: fix fallocate
Fallocate gets off_t parameters passed in, so we should also read them out
accordingly.
Signed-off-by: Alexander Graf <agraf at suse.de>
---
v1 -> v2:
- unbreak 64-bit guests
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9d1c8b2..fdd49b1 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8485,7 +8485,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif /* CONFIG_EVENTFD */
#if defined(CONFIG_FALLOCATE) && defined(TARGET_NR_fallocate)
case TARGET_NR_fallocate:
+#if TARGET_ABI_BITS == 32
+ ret = get_errno(fallocate(arg1, arg2, target_offset64(arg3, arg4),
+ target_offset64(arg5, arg6)));
+#else
ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
+#endif
break;
#endif
#if defined(CONFIG_SYNC_FILE_RANGE)
commit 354a0008270e9167ce89527fdf8f1a85c3a7fb87
Author: Alexander Graf <agraf at suse.de>
Date: Thu Feb 2 02:22:34 2012 +0100
linux-user: Add ioctl for BLKBSZGET
This patch adds the ioctl wrapper definition for BLKBSZGET.
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 5b70f92..eb96a08 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -75,6 +75,7 @@
IOCTL(BLKRASET, 0, TYPE_INT)
IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG))
IOCTL(BLKSSZGET, IOC_R, MK_PTR(TYPE_LONG))
+ IOCTL(BLKBSZGET, IOC_R, MK_PTR(TYPE_INT))
#ifdef FIBMAP
IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG))
#endif
commit 49e9a0775224039701d34b208d8a1da982477fc9
Author: Alexander Graf <agraf at suse.de>
Date: Tue Jan 31 20:11:37 2012 +0100
linux-user: add BLKSSZGET ioctl wrapper
This patch adds an ioctl definition for BLKSSZGET.
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index fd8b7bb..5b70f92 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -74,6 +74,7 @@
IOCTL(BLKFLSBUF, 0, TYPE_NULL)
IOCTL(BLKRASET, 0, TYPE_INT)
IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG))
+ IOCTL(BLKSSZGET, IOC_R, MK_PTR(TYPE_LONG))
#ifdef FIBMAP
IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG))
#endif
commit edafea1330133eb8f6580a1c4f84fc5ec766eb4c
Author: Alexander Graf <agraf at suse.de>
Date: Tue Jan 31 20:10:20 2012 +0100
linux-user: fix BLK ioctl arguments
Some BLK ioctls passed sizeof(x) into a macro that already did sizeof() on
the passed in argument, rendering the size information inside the ioctl be
the size of the host default integer type.
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index f8f3af3..a79b67d 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -832,9 +832,11 @@ struct target_pollfd {
#define TARGET_BLKSECTGET TARGET_IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
#define TARGET_BLKSSZGET TARGET_IO(0x12,104)/* get block device sector size */
/* A jump here: 108-111 have been used for various private purposes. */
-#define TARGET_BLKBSZGET TARGET_IOR(0x12,112,sizeof(int))
-#define TARGET_BLKBSZSET TARGET_IOW(0x12,113,sizeof(int))
-#define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
+#define TARGET_BLKBSZGET TARGET_IOR(0x12,112,int)
+#define TARGET_BLKBSZSET TARGET_IOW(0x12,113,int)
+#define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,abi_ulong)
+ /* return device size in bytes
+ (u64 *arg) */
#define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */
#define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */
#define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
commit 6083abd9aa134c9b0804e584f8279f54e6c90a1c
Author: Alexander Graf <agraf at suse.de>
Date: Tue Jan 31 19:44:41 2012 +0100
linux-user: add struct old_dev_t compat
The compat LOOP_SET_STATUS ioctl uses struct old_dev_t in its passed
struct. That variable type is vastly different between different
architectures. Implement wrapping around it so we can use it.
This fixes running arm kpartx on an x86_64 host for me.
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index fb8c9c9..601618d 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -83,9 +83,9 @@ STRUCT(mixer_info,
/* loop device ioctls */
STRUCT(loop_info,
TYPE_INT, /* lo_number */
- TYPE_SHORT, /* lo_device */
+ TYPE_OLDDEVT, /* lo_device */
TYPE_ULONG, /* lo_inode */
- TYPE_SHORT, /* lo_rdevice */
+ TYPE_OLDDEVT, /* lo_rdevice */
TYPE_INT, /* lo_offset */
TYPE_INT, /* lo_encrypt_type */
TYPE_INT, /* lo_encrypt_key_size */
diff --git a/thunk.c b/thunk.c
index 0657188..8ebbbb4 100644
--- a/thunk.c
+++ b/thunk.c
@@ -46,6 +46,7 @@ static inline const argtype *thunk_type_next(const argtype *type_ptr)
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_PTRVOID:
+ case TYPE_OLDDEVT:
return type_ptr;
case TYPE_PTR:
return thunk_type_next_ptr(type_ptr);
@@ -188,6 +189,33 @@ const argtype *thunk_convert(void *dst, const void *src,
#else
#warning unsupported conversion
#endif
+ case TYPE_OLDDEVT:
+ {
+ uint64_t val = 0;
+ switch (thunk_type_size(type_ptr - 1, !to_host)) {
+ case 2:
+ val = *(uint16_t *)src;
+ break;
+ case 4:
+ val = *(uint32_t *)src;
+ break;
+ case 8:
+ val = *(uint64_t *)src;
+ break;
+ }
+ switch (thunk_type_size(type_ptr - 1, to_host)) {
+ case 2:
+ *(uint16_t *)dst = tswap16(val);
+ break;
+ case 4:
+ *(uint32_t *)dst = tswap32(val);
+ break;
+ case 8:
+ *(uint64_t *)dst = tswap64(val);
+ break;
+ }
+ break;
+ }
case TYPE_ARRAY:
{
int array_length, i, dst_size, src_size;
diff --git a/thunk.h b/thunk.h
index 9810743..5be8f91 100644
--- a/thunk.h
+++ b/thunk.h
@@ -37,6 +37,7 @@ typedef enum argtype {
TYPE_PTR,
TYPE_ARRAY,
TYPE_STRUCT,
+ TYPE_OLDDEVT,
} argtype;
#define MK_PTR(type) TYPE_PTR, type
@@ -104,6 +105,31 @@ static inline int thunk_type_size(const argtype *type_ptr, int is_host)
return TARGET_ABI_BITS / 8;
}
break;
+ case TYPE_OLDDEVT:
+ if (is_host) {
+#if defined(HOST_X86_64)
+ return 8;
+#elif defined(HOST_ALPHA) || defined(HOST_IA64) || defined(HOST_MIPS) || \
+ defined(HOST_PARISC) || defined(HOST_SPARC64)
+ return 4;
+#elif defined(HOST_PPC)
+ return HOST_LONG_SIZE;
+#else
+ return 2;
+#endif
+ } else {
+#if defined(TARGET_X86_64)
+ return 8;
+#elif defined(TARGET_ALPHA) || defined(TARGET_IA64) || defined(TARGET_MIPS) || \
+ defined(TARGET_PARISC) || defined(TARGET_SPARC64)
+ return 4;
+#elif defined(TARGET_PPC)
+ return TARGET_ABI_BITS / 8;
+#else
+ return 2;
+#endif
+ }
+ break;
case TYPE_ARRAY:
size = type_ptr[1];
return size * thunk_type_size_array(type_ptr + 2, is_host);
@@ -141,6 +167,8 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host)
return TARGET_ABI_BITS / 8;
}
break;
+ case TYPE_OLDDEVT:
+ return thunk_type_size(type_ptr, is_host);
case TYPE_ARRAY:
return thunk_type_align_array(type_ptr + 2, is_host);
case TYPE_STRUCT:
commit 56e904ecb2018e30b10e9ec846635ff3b1e1d923
Author: Alexander Graf <agraf at suse.de>
Date: Tue Jan 31 18:42:06 2012 +0100
linux-user: implement device mapper ioctls
This patch implements all ioctls currently implemented by device mapper,
enabling us to run dmsetup and kpartx inside of linux-user.
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 6514502..fd8b7bb 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -345,3 +345,35 @@
IOCTL(VT_SETMODE, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_vt_mode)))
IOCTL(VT_RELDISP, 0, TYPE_INT)
IOCTL(VT_DISALLOCATE, 0, TYPE_INT)
+
+ IOCTL(DM_VERSION, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_REMOVE_ALL, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_LIST_DEVICES, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_DEV_CREATE, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_DEV_REMOVE, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_DEV_RENAME, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_DEV_SUSPEND, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_DEV_STATUS, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_DEV_WAIT, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_TABLE_LOAD, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_TABLE_CLEAR, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_TABLE_DEPS, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_TABLE_STATUS, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_LIST_VERSIONS,IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_TARGET_MSG, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+ IOCTL_SPECIAL(DM_DEV_SET_GEOMETRY, IOC_RW, do_ioctl_dm,
+ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 0e74ee0..9d1c8b2 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -95,6 +95,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#endif
#include <linux/fb.h>
#include <linux/vt.h>
+#include <linux/dm-ioctl.h>
#include "linux_loop.h"
#include "cpu-uname.h"
@@ -3354,6 +3355,231 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
return ret;
}
+static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
+ abi_long cmd, abi_long arg)
+{
+ void *argptr;
+ struct dm_ioctl *host_dm;
+ abi_long guest_data;
+ uint32_t guest_data_size;
+ int target_size;
+ const argtype *arg_type = ie->arg_type;
+ abi_long ret;
+ void *big_buf = NULL;
+ char *host_data;
+
+ arg_type++;
+ target_size = thunk_type_size(arg_type, 0);
+ argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+ if (!argptr) {
+ ret = -TARGET_EFAULT;
+ goto out;
+ }
+ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+ unlock_user(argptr, arg, 0);
+
+ /* buf_temp is too small, so fetch things into a bigger buffer */
+ big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
+ memcpy(big_buf, buf_temp, target_size);
+ buf_temp = big_buf;
+ host_dm = big_buf;
+
+ guest_data = arg + host_dm->data_start;
+ if ((guest_data - arg) < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ guest_data_size = host_dm->data_size - host_dm->data_start;
+ host_data = (char*)host_dm + host_dm->data_start;
+
+ argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
+ switch (ie->host_cmd) {
+ case DM_REMOVE_ALL:
+ case DM_LIST_DEVICES:
+ case DM_DEV_CREATE:
+ case DM_DEV_REMOVE:
+ case DM_DEV_SUSPEND:
+ case DM_DEV_STATUS:
+ case DM_DEV_WAIT:
+ case DM_TABLE_STATUS:
+ case DM_TABLE_CLEAR:
+ case DM_TABLE_DEPS:
+ case DM_LIST_VERSIONS:
+ /* no input data */
+ break;
+ case DM_DEV_RENAME:
+ case DM_DEV_SET_GEOMETRY:
+ /* data contains only strings */
+ memcpy(host_data, argptr, guest_data_size);
+ break;
+ case DM_TARGET_MSG:
+ memcpy(host_data, argptr, guest_data_size);
+ *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
+ break;
+ case DM_TABLE_LOAD:
+ {
+ void *gspec = argptr;
+ void *cur_data = host_data;
+ const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
+ int spec_size = thunk_type_size(arg_type, 0);
+ int i;
+
+ for (i = 0; i < host_dm->target_count; i++) {
+ struct dm_target_spec *spec = cur_data;
+ uint32_t next;
+ int slen;
+
+ thunk_convert(spec, gspec, arg_type, THUNK_HOST);
+ slen = strlen((char*)gspec + spec_size) + 1;
+ next = spec->next;
+ spec->next = sizeof(*spec) + slen;
+ strcpy((char*)&spec[1], gspec + spec_size);
+ gspec += next;
+ cur_data += spec->next;
+ }
+ break;
+ }
+ default:
+ ret = -TARGET_EINVAL;
+ goto out;
+ }
+ unlock_user(argptr, guest_data, 0);
+
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ if (!is_error(ret)) {
+ guest_data = arg + host_dm->data_start;
+ guest_data_size = host_dm->data_size - host_dm->data_start;
+ argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
+ switch (ie->host_cmd) {
+ case DM_REMOVE_ALL:
+ case DM_DEV_CREATE:
+ case DM_DEV_REMOVE:
+ case DM_DEV_RENAME:
+ case DM_DEV_SUSPEND:
+ case DM_DEV_STATUS:
+ case DM_TABLE_LOAD:
+ case DM_TABLE_CLEAR:
+ case DM_TARGET_MSG:
+ case DM_DEV_SET_GEOMETRY:
+ /* no return data */
+ break;
+ case DM_LIST_DEVICES:
+ {
+ struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
+ uint32_t remaining_data = guest_data_size;
+ void *cur_data = argptr;
+ const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
+ int nl_size = 12; /* can't use thunk_size due to alignment */
+
+ while (1) {
+ uint32_t next = nl->next;
+ if (next) {
+ nl->next = nl_size + (strlen(nl->name) + 1);
+ }
+ if (remaining_data < nl->next) {
+ host_dm->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
+ thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
+ strcpy(cur_data + nl_size, nl->name);
+ cur_data += nl->next;
+ remaining_data -= nl->next;
+ if (!next) {
+ break;
+ }
+ nl = (void*)nl + next;
+ }
+ break;
+ }
+ case DM_DEV_WAIT:
+ case DM_TABLE_STATUS:
+ {
+ struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
+ void *cur_data = argptr;
+ const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
+ int spec_size = thunk_type_size(arg_type, 0);
+ int i;
+
+ for (i = 0; i < host_dm->target_count; i++) {
+ uint32_t next = spec->next;
+ int slen = strlen((char*)&spec[1]) + 1;
+ spec->next = (cur_data - argptr) + spec_size + slen;
+ if (guest_data_size < spec->next) {
+ host_dm->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
+ thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
+ strcpy(cur_data + spec_size, (char*)&spec[1]);
+ cur_data = argptr + spec->next;
+ spec = (void*)host_dm + host_dm->data_start + next;
+ }
+ break;
+ }
+ case DM_TABLE_DEPS:
+ {
+ void *hdata = (void*)host_dm + host_dm->data_start;
+ int count = *(uint32_t*)hdata;
+ uint64_t *hdev = hdata + 8;
+ uint64_t *gdev = argptr + 8;
+ int i;
+
+ *(uint32_t*)argptr = tswap32(count);
+ for (i = 0; i < count; i++) {
+ *gdev = tswap64(*hdev);
+ gdev++;
+ hdev++;
+ }
+ break;
+ }
+ case DM_LIST_VERSIONS:
+ {
+ struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
+ uint32_t remaining_data = guest_data_size;
+ void *cur_data = argptr;
+ const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
+ int vers_size = thunk_type_size(arg_type, 0);
+
+ while (1) {
+ uint32_t next = vers->next;
+ if (next) {
+ vers->next = vers_size + (strlen(vers->name) + 1);
+ }
+ if (remaining_data < vers->next) {
+ host_dm->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
+ thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
+ strcpy(cur_data + vers_size, vers->name);
+ cur_data += vers->next;
+ remaining_data -= vers->next;
+ if (!next) {
+ break;
+ }
+ vers = (void*)vers + next;
+ }
+ break;
+ }
+ default:
+ ret = -TARGET_EINVAL;
+ goto out;
+ }
+ unlock_user(argptr, guest_data, guest_data_size);
+
+ argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+ if (!argptr) {
+ ret = -TARGET_EFAULT;
+ goto out;
+ }
+ thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+ unlock_user(argptr, arg, target_size);
+ }
+out:
+ if (big_buf) {
+ free(big_buf);
+ }
+ return ret;
+}
+
static IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 41f0ff8..f8f3af3 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -989,6 +989,24 @@ struct target_pollfd {
#define TARGET_VT_RELDISP 0x5605
#define TARGET_VT_DISALLOCATE 0x5608
+/* device mapper */
+#define TARGET_DM_VERSION TARGET_IOWRU(0xfd, 0x00)
+#define TARGET_DM_REMOVE_ALL TARGET_IOWRU(0xfd, 0x01)
+#define TARGET_DM_LIST_DEVICES TARGET_IOWRU(0xfd, 0x02)
+#define TARGET_DM_DEV_CREATE TARGET_IOWRU(0xfd, 0x03)
+#define TARGET_DM_DEV_REMOVE TARGET_IOWRU(0xfd, 0x04)
+#define TARGET_DM_DEV_RENAME TARGET_IOWRU(0xfd, 0x05)
+#define TARGET_DM_DEV_SUSPEND TARGET_IOWRU(0xfd, 0x06)
+#define TARGET_DM_DEV_STATUS TARGET_IOWRU(0xfd, 0x07)
+#define TARGET_DM_DEV_WAIT TARGET_IOWRU(0xfd, 0x08)
+#define TARGET_DM_TABLE_LOAD TARGET_IOWRU(0xfd, 0x09)
+#define TARGET_DM_TABLE_CLEAR TARGET_IOWRU(0xfd, 0x0a)
+#define TARGET_DM_TABLE_DEPS TARGET_IOWRU(0xfd, 0x0b)
+#define TARGET_DM_TABLE_STATUS TARGET_IOWRU(0xfd, 0x0c)
+#define TARGET_DM_LIST_VERSIONS TARGET_IOWRU(0xfd, 0x0d)
+#define TARGET_DM_TARGET_MSG TARGET_IOWRU(0xfd, 0x0e)
+#define TARGET_DM_DEV_SET_GEOMETRY TARGET_IOWRU(0xfd, 0x0f)
+
/* from asm/termbits.h */
#define TARGET_NCC 8
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index c370125..fb8c9c9 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -186,6 +186,42 @@ STRUCT(vt_mode,
TYPE_SHORT, /* acqsig */
TYPE_SHORT) /* frsig */
+STRUCT(dm_ioctl,
+ MK_ARRAY(TYPE_INT, 3), /* version */
+ TYPE_INT, /* data_size */
+ TYPE_INT, /* data_start */
+ TYPE_INT, /* target_count*/
+ TYPE_INT, /* open_count */
+ TYPE_INT, /* flags */
+ TYPE_INT, /* event_nr */
+ TYPE_INT, /* padding */
+ TYPE_ULONGLONG, /* dev */
+ MK_ARRAY(TYPE_CHAR, 128), /* name */
+ MK_ARRAY(TYPE_CHAR, 129), /* uuid */
+ MK_ARRAY(TYPE_CHAR, 7)) /* data */
+
+STRUCT(dm_target_spec,
+ TYPE_ULONGLONG, /* sector_start */
+ TYPE_ULONGLONG, /* length */
+ TYPE_INT, /* status */
+ TYPE_INT, /* next */
+ MK_ARRAY(TYPE_CHAR, 16)) /* target_type */
+
+STRUCT(dm_target_deps,
+ TYPE_INT, /* count */
+ TYPE_INT) /* padding */
+
+STRUCT(dm_name_list,
+ TYPE_ULONGLONG, /* dev */
+ TYPE_INT) /* next */
+
+STRUCT(dm_target_versions,
+ TYPE_INT, /* next */
+ MK_ARRAY(TYPE_INT, 3)) /* version*/
+
+STRUCT(dm_target_msg,
+ TYPE_ULONGLONG) /* sector */
+
STRUCT(fiemap_extent,
TYPE_ULONGLONG, /* fe_logical */
TYPE_ULONGLONG, /* fe_physical */
commit 84803b87a183bd71963584c3be5ca838d32c55df
Author: Fabio Erculiani <lxnay at sabayon.org>
Date: Tue Jan 3 09:38:35 2012 +0000
linux-user: target_argv is placed on ts->bprm->argv and can't be freed()
TaskState contains linux_bprm struct which encapsulates argv among
other things.
argv might be used around the code and is expected to contain valid
data. Before this patch, ts->bprm->argv was NULL due to it being
freed right after loader_exec().
Signed-off-by: Fabio Erculiani <lxnay at sabayon.org>
Acked-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/main.c b/linux-user/main.c
index 962677e..2570140 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3486,11 +3486,6 @@ int main(int argc, char **argv, char **envp)
_exit(1);
}
- for (i = 0; i < target_argc; i++) {
- free(target_argv[i]);
- }
- free(target_argv);
-
for (wrk = target_environ; *wrk; wrk++) {
free(*wrk);
}
commit e0e65bee16ae8515315d2bad02e021f3fb5dd236
Author: Fabio Erculiani <lxnay at sabayon.org>
Date: Tue Jan 3 09:38:34 2012 +0000
linux-user: improve fake /proc/self/stat making `ps` not segfault.
With the current fake /proc/self/stat implementation `ps` is
segfaulting because it expects to read PID and argv[0] as first and
second field respectively, with the latter being enclosed between
backets.
Reproducing is as easy as running: `ps` inside qemu-user chroot
with /proc mounted.
Signed-off-by: Fabio Erculiani <lxnay at sabayon.org>
Acked-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9f5e53a..0e74ee0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4662,11 +4662,22 @@ static int open_self_stat(void *cpu_env, int fd)
int len;
uint64_t val = 0;
- if (i == 27) {
- /* stack bottom */
- val = start_stack;
+ if (i == 0) {
+ /* pid */
+ val = getpid();
+ snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
+ } else if (i == 1) {
+ /* app name */
+ snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
+ } else if (i == 27) {
+ /* stack bottom */
+ val = start_stack;
+ snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
+ } else {
+ /* for the rest, there is MasterCard */
+ snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
}
- snprintf(buf, sizeof(buf), "%"PRId64 "%c", val, i == 43 ? '\n' : ' ');
+
len = strlen(buf);
if (write(fd, buf, len) != len) {
return -1;
commit 50d30c267563bf492fd403dd23abc7888f3e220c
Author: Benoît Canet <benoit.canet at gmail.com>
Date: Fri Mar 23 08:36:54 2012 +0100
qed: remove incoming live migration blocker
Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qed.c b/block/qed.c
index aea2772..366cde7 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -498,12 +498,6 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
s->need_check_timer = qemu_new_timer_ns(vm_clock,
qed_need_check_timer_cb, s);
- error_set(&s->migration_blocker,
- QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
- "qed", bs->device_name, "live migration");
- migrate_add_blocker(s->migration_blocker);
-
-
out:
if (ret) {
qed_free_l2_cache(&s->l2_cache);
@@ -516,9 +510,6 @@ static void bdrv_qed_close(BlockDriverState *bs)
{
BDRVQEDState *s = bs->opaque;
- migrate_del_blocker(s->migration_blocker);
- error_free(s->migration_blocker);
-
qed_cancel_need_check_timer(s);
qemu_free_timer(s->need_check_timer);
diff --git a/block/qed.h b/block/qed.h
index 62624a1..c716772 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -169,8 +169,6 @@ typedef struct {
/* Periodic flush and clear need check flag */
QEMUTimer *need_check_timer;
-
- Error *migration_blocker;
} BDRVQEDState;
enum {
commit 2d1f3c2360053dec7dacc0292f52cff17104feff
Author: Benoît Canet <benoit.canet at gmail.com>
Date: Fri Mar 23 08:36:53 2012 +0100
qed: honor BDRV_O_INCOMING for incoming live migration
From original commit with Patchwork-id: 31108 by
Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
"The QED image format includes a file header bit to mark images dirty.
QED normally checks dirty images on open and fixes inconsistent
metadata. This is undesirable during live migration since the dirty bit
may be set if the source host is modifying the image file. The check
should be postponed until migration completes.
Skip operations that modify the image file if the BDRV_O_INCOMING flag
is set."
Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qed.c b/block/qed.c
index a5e9d57..aea2772 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -450,7 +450,7 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
* feature is no longer valid.
*/
if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
- !bdrv_is_read_only(bs->file)) {
+ !bdrv_is_read_only(bs->file) && !(flags & BDRV_O_INCOMING)) {
s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK;
ret = qed_write_header_sync(s);
@@ -477,7 +477,8 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
* potentially inconsistent images to be opened read-only. This can
* aid data recovery from an otherwise inconsistent image.
*/
- if (!bdrv_is_read_only(bs->file)) {
+ if (!bdrv_is_read_only(bs->file) &&
+ !(flags & BDRV_O_INCOMING)) {
BdrvCheckResult result = {0};
ret = qed_check(s, &result, true);
commit 901862cbf49639aaef23a575d40ae81282b6fcfc
Author: Benoît Canet <benoit.canet at gmail.com>
Date: Fri Mar 23 08:36:52 2012 +0100
migration: clear BDRV_O_INCOMING flags on end of incoming live migration
Signed-off-by: Benoît Canet <benoit.canet at gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/migration.c b/migration.c
index 8c119ba..94f7839 100644
--- a/migration.c
+++ b/migration.c
@@ -91,6 +91,7 @@ void process_incoming_migration(QEMUFile *f)
qemu_announce_self();
DPRINTF("successfully loaded vm state\n");
+ bdrv_clear_incoming_migration_all();
/* Make sure all file formats flush their mutable metadata */
bdrv_invalidate_cache_all();
commit c82954e529929c2d650589d8bccaaf19dec33431
Author: Benoît Canet <benoit.canet at gmail.com>
Date: Fri Mar 23 08:36:51 2012 +0100
qed: add bdrv_invalidate_cache to be called after incoming live migration
The QED image is reopened to flush metadata and check consistency.
Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qed.c b/block/qed.c
index 19d87f3..a5e9d57 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1510,6 +1510,15 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
return ret;
}
+static void bdrv_qed_invalidate_cache(BlockDriverState *bs)
+{
+ BDRVQEDState *s = bs->opaque;
+
+ bdrv_qed_close(bs);
+ memset(s, 0, sizeof(BDRVQEDState));
+ bdrv_qed_open(bs, bs->open_flags);
+}
+
static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result)
{
BDRVQEDState *s = bs->opaque;
@@ -1561,6 +1570,7 @@ static BlockDriver bdrv_qed = {
.bdrv_getlength = bdrv_qed_getlength,
.bdrv_get_info = bdrv_qed_get_info,
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
+ .bdrv_invalidate_cache = bdrv_qed_invalidate_cache,
.bdrv_check = bdrv_qed_check,
};
commit ed9d4205cecb2f6c06821cb9d8fe9e1ca5f9b8ab
Author: Benoît Canet <benoit.canet at gmail.com>
Date: Fri Mar 23 08:36:50 2012 +0100
blockdev: open images with BDRV_O_INCOMING on incoming live migration
Open images with BDRV_O_INCOMING in order to inform block drivers
that an incoming live migration is coming.
Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/blockdev.c b/blockdev.c
index 4d17486..0c2440e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -595,6 +595,10 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
bdrv_flags |= BDRV_O_COPY_ON_READ;
}
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ bdrv_flags |= BDRV_O_INCOMING;
+ }
+
if (media == MEDIA_CDROM) {
/* CDROM is fine for any interface, don't check. */
ro = 1;
commit 077892696b900ebf88052fef917367213db80477
Author: Benoît Canet <benoit.canet at gmail.com>
Date: Fri Mar 23 08:36:49 2012 +0100
block: add a function to clear incoming live migration flags
This function will clear all BDRV_O_INCOMING flags.
Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index b3117ef..c0c90f0 100644
--- a/block.c
+++ b/block.c
@@ -3624,6 +3624,15 @@ void bdrv_invalidate_cache_all(void)
}
}
+void bdrv_clear_incoming_migration_all(void)
+{
+ BlockDriverState *bs;
+
+ QTAILQ_FOREACH(bs, &bdrv_states, list) {
+ bs->open_flags = bs->open_flags & ~(BDRV_O_INCOMING);
+ }
+}
+
int bdrv_flush(BlockDriverState *bs)
{
Coroutine *co;
diff --git a/block.h b/block.h
index 5151dea..f163e54 100644
--- a/block.h
+++ b/block.h
@@ -229,6 +229,8 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
void bdrv_invalidate_cache(BlockDriverState *bs);
void bdrv_invalidate_cache_all(void);
+void bdrv_clear_incoming_migration_all(void);
+
/* Ensure contents are flushed to disk. */
int bdrv_flush(BlockDriverState *bs);
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
commit ccb1f4a7b32fbebcf0d49beab1d2614f0a657d5a
Author: Benoît Canet <benoit.canet at gmail.com>
Date: Fri Mar 23 08:36:48 2012 +0100
block: Add new BDRV_O_INCOMING flag to notice incoming live migration
From original patch with Patchwork-id: 31110 by
Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
"Add a flag to indicate that incoming migration is pending and care needs
to be taken for data consistency. Block drivers should not modify the
image file before incoming migration is complete since the migration
source host is still using the image file."
The rationale for not using bdrv->read_only is the following.
"Unfortunately this is not possible because too many other places in QEMU
test bdrv_is_read_only() and use it for their own evil purposes. For
example, ide_init_drive() will error out because read-only harddisks are
not supported. We're mixing guest and host side read-only concepts so
this simpler alternative does not work."
Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.h b/block.h
index 4e99e18..5151dea 100644
--- a/block.h
+++ b/block.h
@@ -78,6 +78,7 @@ typedef struct BlockDevOps {
#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */
#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */
#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */
+#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
commit 5a67a1048e1294b35940e7432d57d8cd801e6571
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date: Mon Mar 26 21:22:10 2012 -0300
block stream: close unused files and update ->backing_hd
Close the now unused images that were part of the previous backing file
chain and adjust ->backing_hd, backing_filename and backing_format
properly.
Fixes https://bugzilla.redhat.com/show_bug.cgi?id=801449
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/stream.c b/block/stream.c
index 61ff7a2..0efe1ad 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -76,6 +76,39 @@ static int coroutine_fn stream_populate(BlockDriverState *bs,
return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov);
}
+static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
+ const char *base_id)
+{
+ BlockDriverState *intermediate;
+ intermediate = top->backing_hd;
+
+ while (intermediate) {
+ BlockDriverState *unused;
+
+ /* reached base */
+ if (intermediate == base) {
+ break;
+ }
+
+ unused = intermediate;
+ intermediate = intermediate->backing_hd;
+ unused->backing_hd = NULL;
+ bdrv_delete(unused);
+ }
+ top->backing_hd = base;
+
+ pstrcpy(top->backing_file, sizeof(top->backing_file), "");
+ pstrcpy(top->backing_format, sizeof(top->backing_format), "");
+ if (base_id) {
+ pstrcpy(top->backing_file, sizeof(top->backing_file), base_id);
+ if (base->drv) {
+ pstrcpy(top->backing_format, sizeof(top->backing_format),
+ base->drv->format_name);
+ }
+ }
+
+}
+
/*
* Given an image chain: [BASE] -> [INTER1] -> [INTER2] -> [TOP]
*
@@ -223,6 +256,7 @@ retry:
base_id = s->backing_file_id;
}
ret = bdrv_change_backing_file(bs, base_id, NULL);
+ close_unused_images(bs, base, base_id);
}
qemu_vfree(buf);
commit 28d3d1658a3692f9c34c3ecce14941faa1d2fe92
Author: Stefan Weil <sw at weilnetz.de>
Date: Wed Mar 14 19:57:24 2012 +0100
qemu-iotests: Fix call syntax for qemu-io
qemu-io requires options first, then fixed parameters.
GNU getopt also allows options at the end, but POSIX getopt
doesn't. Try "export POSIXLY_CORRECT=y" to get the POSIX
behaviour with GNU getopt, too.
Cc: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009
index f7262b5..25368c8 100755
--- a/tests/qemu-iotests/009
+++ b/tests/qemu-iotests/009
@@ -53,10 +53,10 @@ _make_test_img $size
echo
echo "creating pattern"
$QEMU_IO \
- -c "write 2048k 4k -P 65" \
+ -c "write -P 65 2048k 4k" \
-c "write 4k 4k" \
-c "write 9M 4k" \
- -c "read 2044k 8k -P 65 -s 4k -l 4k" \
+ -c "read -P 65 -s 4k -l 4k 2044k 8k" \
$TEST_IMG | _filter_qemu_io
echo
diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010
index e3205aa..7b57929 100755
--- a/tests/qemu-iotests/010
+++ b/tests/qemu-iotests/010
@@ -53,11 +53,11 @@ _make_test_img $size
echo
echo "creating pattern"
$QEMU_IO \
- -c "write 2048k 4k -P 165" \
+ -c "write -P 165 2048k 4k" \
-c "write 64k 4k" \
-c "write 9M 4k" \
- -c "write 2044k 4k -P 165" \
- -c "write 8M 4k -P 99" \
+ -c "write -P 165 2044k 4k" \
+ -c "write -P 99 8M 4k" \
-c "read -P 165 2044k 8k" \
$TEST_IMG | _filter_qemu_io
diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011
index 59df1ae..b03df68 100755
--- a/tests/qemu-iotests/011
+++ b/tests/qemu-iotests/011
@@ -60,7 +60,7 @@ for i in `seq 1 10`; do
# Note that we filter away the actual offset. That's because qemu
# may re-order the two aio requests. We only want to make sure the
# filesystem isn't corrupted afterwards anyway.
- $QEMU_IO $TEST_IMG -c "aio_write $off1 1M" -c "aio_write $off2 1M" | \
+ $QEMU_IO -c "aio_write $off1 1M" -c "aio_write $off2 1M" $TEST_IMG | \
_filter_qemu_io | \
sed -e 's/bytes at offset [0-9]*/bytes at offset XXX/g'
done
commit 21af81488799e2290cb2e58eb2a91d1d8044ebc4
Author: Stefan Weil <sw at weilnetz.de>
Date: Wed Mar 14 19:57:23 2012 +0100
qemu-iotests: Fix call syntax for qemu-img
qemu-img requires first options, then file name, then size.
GNU getopt also allows options at the end, but POSIX getopt
doesn't. Try "export POSIXLY_CORRECT=y" to get the POSIX
behaviour with GNU getopt, too.
Cc: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 26811ca..4cb8dae 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -57,16 +57,21 @@ _make_test_img()
{
# extra qemu-img options can be added by tests
# at least one argument (the image size) needs to be added
- local extra_img_options=$*
+ local extra_img_options=""
local cluster_size_filter="s# cluster_size=[0-9]\\+##g"
+ local image_size=$*
+ if [ "$1" = "-b" ]; then
+ extra_img_options="$1 $2"
+ image_size=$3
+ fi
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
extra_img_options="-o cluster_size=$CLUSTER_SIZE $extra_img_options"
cluster_size_filter=""
fi
# XXX(hch): have global image options?
- $QEMU_IMG create -f $IMGFMT $TEST_IMG $extra_img_options | \
+ $QEMU_IMG create -f $IMGFMT $extra_img_options $TEST_IMG $image_size | \
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" | \
sed -e "s#$TEST_DIR#TEST_DIR#g" | \
sed -e "s#$IMGFMT#IMGFMT#g" | \
commit f394f1feb921d5a4b278e7ac95bdaa49e34a52f2
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Feb 16 16:55:01 2012 +0100
qemu-iotests: Test unknown qcow2 header extensions
The immportant thing here is that header extensions don't get silently
dropped when the header is rewritten, e.g. during a rebase.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
new file mode 100755
index 0000000..6365f28
--- /dev/null
+++ b/tests/qemu-iotests/031
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# Test that all qcow2 header extensions survive a header rewrite
+#
+# Copyright (C) 2011 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+# This tests qcow2-specific low-level functionality
+_supported_fmt qcow2
+_supported_proto generic
+_supported_os Linux
+
+CLUSTER_SIZE=65536
+echo
+echo === Create image with unknown header extension ===
+echo
+_make_test_img 64M
+./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
+./qcow2.py $TEST_IMG dump-header
+_check_test_img
+
+echo
+echo === Rewrite header with no backing file ===
+echo
+$QEMU_IMG rebase -u -b "" $TEST_IMG
+./qcow2.py $TEST_IMG dump-header
+_check_test_img
+
+echo
+echo === Add a backing file and format ===
+echo
+$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
+./qcow2.py $TEST_IMG dump-header
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
new file mode 100644
index 0000000..0f1bf68
--- /dev/null
+++ b/tests/qemu-iotests/031.out
@@ -0,0 +1,76 @@
+QA output created by 031
+
+=== Create image with unknown header extension ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536
+magic 0x514649fb
+version 2
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+No errors were found on the image.
+
+=== Rewrite header with no backing file ===
+
+magic 0x514649fb
+version 2
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+No errors were found on the image.
+
+=== Add a backing file and format ===
+
+magic 0x514649fb
+version 2
+backing_file_offset 0x90
+backing_file_size 0x17
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+
+Header extension:
+magic 0xe2792aca
+length 11
+data 'host_device'
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index b549f10..1742ede 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -37,3 +37,4 @@
028 rw backing auto
029 rw auto quick
030 rw auto
+031 rw auto quick
commit 6e19b3c4e0b40b08ccb550a0c0a65798f3a17ac8
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Feb 15 16:36:03 2012 +0100
qemu-iotests: qcow2.py
This adds a tool that is meant to inspect and edit qcow2 files in a
low-level way, that wouldn't be possible with qemu-img/io, for example
by adding yet unknown extensions or flags. This way we can test whether
qemu deals properly with future backwards compatible extensions.
For now, let's start with the image header and header extensions.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
new file mode 100755
index 0000000..bfb47e8
--- /dev/null
+++ b/tests/qemu-iotests/qcow2.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python
+
+import sys
+import struct
+import string
+
+class QcowHeaderExtension:
+
+ def __init__(self, magic, length, data):
+ self.magic = magic
+ self.length = length
+ self.data = data
+
+ @classmethod
+ def create(cls, magic, data):
+ return QcowHeaderExtension(magic, len(data), data)
+
+class QcowHeader:
+
+ uint32_t = 'I'
+ uint64_t = 'Q'
+
+ fields = [
+ # Version 2 header fields
+ [ uint32_t, '%#x', 'magic' ],
+ [ uint32_t, '%d', 'version' ],
+ [ uint64_t, '%#x', 'backing_file_offset' ],
+ [ uint32_t, '%#x', 'backing_file_size' ],
+ [ uint32_t, '%d', 'cluster_bits' ],
+ [ uint64_t, '%d', 'size' ],
+ [ uint32_t, '%d', 'crypt_method' ],
+ [ uint32_t, '%d', 'l1_size' ],
+ [ uint64_t, '%#x', 'l1_table_offset' ],
+ [ uint64_t, '%#x', 'refcount_table_offset' ],
+ [ uint32_t, '%d', 'refcount_table_clusters' ],
+ [ uint32_t, '%d', 'nb_snapshots' ],
+ [ uint64_t, '%#x', 'snapshot_offset' ],
+ ];
+
+ fmt = '>' + ''.join(field[0] for field in fields)
+
+ def __init__(self, fd):
+
+ buf_size = struct.calcsize(QcowHeader.fmt)
+
+ fd.seek(0)
+ buf = fd.read(buf_size)
+
+ header = struct.unpack(QcowHeader.fmt, buf)
+ self.__dict__ = dict((field[2], header[i])
+ for i, field in enumerate(QcowHeader.fields))
+
+ self.cluster_size = 1 << self.cluster_bits
+
+ fd.seek(self.get_header_length())
+ self.load_extensions(fd)
+
+ if self.backing_file_offset:
+ fd.seek(self.backing_file_offset)
+ self.backing_file = fd.read(self.backing_file_size)
+ else:
+ self.backing_file = None
+
+ def get_header_length(self):
+ if self.version == 2:
+ return 72
+ else:
+ raise Exception("version != 2 not supported")
+
+ def load_extensions(self, fd):
+ self.extensions = []
+
+ if self.backing_file_offset != 0:
+ end = min(self.cluster_size, self.backing_file_offset)
+ else:
+ end = self.cluster_size
+
+ while fd.tell() < end:
+ (magic, length) = struct.unpack('>II', fd.read(8))
+ if magic == 0:
+ break
+ else:
+ padded = (length + 7) & ~7
+ data = fd.read(padded)
+ self.extensions.append(QcowHeaderExtension(magic, length, data))
+
+ def update_extensions(self, fd):
+
+ fd.seek(self.get_header_length())
+ extensions = self.extensions
+ extensions.append(QcowHeaderExtension(0, 0, ""))
+ for ex in extensions:
+ buf = struct.pack('>II', ex.magic, ex.length)
+ fd.write(buf)
+ fd.write(ex.data)
+
+ if self.backing_file != None:
+ self.backing_file_offset = fd.tell()
+ fd.write(self.backing_file)
+
+ if fd.tell() > self.cluster_size:
+ raise Exception("I think I just broke the image...")
+
+
+ def update(self, fd):
+ header_bytes = self.get_header_length()
+
+ self.update_extensions(fd)
+
+ fd.seek(0)
+ header = tuple(self.__dict__[f] for t, p, f in QcowHeader.fields)
+ buf = struct.pack(QcowHeader.fmt, *header)
+ buf = buf[0:header_bytes-1]
+ fd.write(buf)
+
+ def dump(self):
+ for f in QcowHeader.fields:
+ print "%-25s" % f[2], f[1] % self.__dict__[f[2]]
+ print ""
+
+ def dump_extensions(self):
+ for ex in self.extensions:
+
+ data = ex.data[:ex.length]
+ if all(c in string.printable for c in data):
+ data = "'%s'" % data
+ else:
+ data = "<binary>"
+
+ print "Header extension:"
+ print "%-25s %#x" % ("magic", ex.magic)
+ print "%-25s %d" % ("length", ex.length)
+ print "%-25s %s" % ("data", data)
+ print ""
+
+
+def cmd_dump_header(fd):
+ h = QcowHeader(fd)
+ h.dump()
+ h.dump_extensions()
+
+def cmd_add_header_ext(fd, magic, data):
+ try:
+ magic = int(magic, 0)
+ except:
+ print "'%s' is not a valid magic number" % magic
+ sys.exit(1)
+
+ h = QcowHeader(fd)
+ h.extensions.append(QcowHeaderExtension.create(magic, data))
+ h.update(fd)
+
+def cmd_del_header_ext(fd, magic):
+ try:
+ magic = int(magic, 0)
+ except:
+ print "'%s' is not a valid magic number" % magic
+ sys.exit(1)
+
+ h = QcowHeader(fd)
+ found = False
+
+ for ex in h.extensions:
+ if ex.magic == magic:
+ found = True
+ h.extensions.remove(ex)
+
+ if not found:
+ print "No such header extension"
+ return
+
+ h.update(fd)
+
+cmds = [
+ [ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
+ [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ],
+ [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ],
+]
+
+def main(filename, cmd, args):
+ fd = open(filename, "r+b")
+ try:
+ for name, handler, num_args, desc in cmds:
+ if name != cmd:
+ continue
+ elif len(args) != num_args:
+ usage()
+ return
+ else:
+ handler(fd, *args)
+ return
+ print "Unknown command '%s'" % cmd
+ finally:
+ fd.close()
+
+def usage():
+ print "Usage: %s <file> <cmd> [<arg>, ...]" % sys.argv[0]
+ print ""
+ print "Supported commands:"
+ for name, handler, num_args, desc in cmds:
+ print " %-20s - %s" % (name, desc)
+
+if len(sys.argv) < 3:
+ usage()
+ sys.exit(1)
+
+main(sys.argv[1], sys.argv[2], sys.argv[3:])
commit eb09218077a495bc55d84de91f448f72fe78a60b
Author: Liu Yuan <tailai.ly at taobao.com>
Date: Tue Apr 3 18:04:21 2012 +0800
sheepdog: fix send req helpers
We should return if reading of the header fails.
Cc: Kevin Wolf <kwolf at redhat.com>
Cc: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
Signed-off-by: Liu Yuan <tailai.ly at taobao.com>
Acked-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 1248534..3eaf625 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -510,6 +510,7 @@ static int send_req(int sockfd, SheepdogReq *hdr, void *data,
ret = qemu_send_full(sockfd, hdr, sizeof(*hdr), 0);
if (ret < sizeof(*hdr)) {
error_report("failed to send a req, %s", strerror(errno));
+ return ret;
}
ret = qemu_send_full(sockfd, data, *wlen, 0);
@@ -528,6 +529,7 @@ static int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
ret = qemu_co_send(sockfd, hdr, sizeof(*hdr));
if (ret < sizeof(*hdr)) {
error_report("failed to send a req, %s", strerror(errno));
+ return ret;
}
ret = qemu_co_send(sockfd, data, *wlen);
commit 47622c44d0d9a717c1a8f7f5fec6c25ff3b30eec
Author: Liu Yuan <tailai.ly at taobao.com>
Date: Wed Apr 4 04:03:58 2012 +0800
sheepdog: implement SD_OP_FLUSH_VDI operation
Flush operation is supposed to flush the write-back cache of
sheepdog cluster.
By issuing flush operation, we can assure the Guest of data
reaching the sheepdog cluster storage.
Cc: Kevin Wolf <kwolf at redhat.com>
Cc: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
Signed-off-by: Liu Yuan <tailai.ly at taobao.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 00276f6..1248534 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -32,9 +32,11 @@
#define SD_OP_RELEASE_VDI 0x13
#define SD_OP_GET_VDI_INFO 0x14
#define SD_OP_READ_VDIS 0x15
+#define SD_OP_FLUSH_VDI 0x16
#define SD_FLAG_CMD_WRITE 0x01
#define SD_FLAG_CMD_COW 0x02
+#define SD_FLAG_CMD_CACHE 0x04
#define SD_RES_SUCCESS 0x00 /* Success */
#define SD_RES_UNKNOWN 0x01 /* Unknown error */
@@ -293,10 +295,12 @@ typedef struct BDRVSheepdogState {
char name[SD_MAX_VDI_LEN];
int is_snapshot;
+ uint8_t cache_enabled;
char *addr;
char *port;
int fd;
+ int flush_fd;
CoMutex lock;
Coroutine *co_send;
@@ -516,6 +520,23 @@ static int send_req(int sockfd, SheepdogReq *hdr, void *data,
return ret;
}
+static int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
+ unsigned int *wlen)
+{
+ int ret;
+
+ ret = qemu_co_send(sockfd, hdr, sizeof(*hdr));
+ if (ret < sizeof(*hdr)) {
+ error_report("failed to send a req, %s", strerror(errno));
+ }
+
+ ret = qemu_co_send(sockfd, data, *wlen);
+ if (ret < *wlen) {
+ error_report("failed to send a req, %s", strerror(errno));
+ }
+
+ return ret;
+}
static int do_req(int sockfd, SheepdogReq *hdr, void *data,
unsigned int *wlen, unsigned int *rlen)
{
@@ -550,6 +571,40 @@ out:
return ret;
}
+static int do_co_req(int sockfd, SheepdogReq *hdr, void *data,
+ unsigned int *wlen, unsigned int *rlen)
+{
+ int ret;
+
+ socket_set_block(sockfd);
+ ret = send_co_req(sockfd, hdr, data, wlen);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
+ if (ret < sizeof(*hdr)) {
+ error_report("failed to get a rsp, %s", strerror(errno));
+ goto out;
+ }
+
+ if (*rlen > hdr->data_length) {
+ *rlen = hdr->data_length;
+ }
+
+ if (*rlen) {
+ ret = qemu_co_recv(sockfd, data, *rlen);
+ if (ret < *rlen) {
+ error_report("failed to get the data, %s", strerror(errno));
+ goto out;
+ }
+ }
+ ret = 0;
+out:
+ socket_set_nonblock(sockfd);
+ return ret;
+}
+
static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
struct iovec *iov, int niov, int create,
enum AIOCBState aiocb_type);
@@ -900,6 +955,10 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
hdr.flags = SD_FLAG_CMD_WRITE | flags;
}
+ if (s->cache_enabled) {
+ hdr.flags |= SD_FLAG_CMD_CACHE;
+ }
+
hdr.oid = oid;
hdr.cow_oid = old_oid;
hdr.copies = s->inode.nr_copies;
@@ -942,7 +1001,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
unsigned int datalen, uint64_t offset,
- int write, int create)
+ int write, int create, uint8_t cache)
{
SheepdogObjReq hdr;
SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr;
@@ -965,6 +1024,11 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
rlen = datalen;
hdr.opcode = SD_OP_READ_OBJ;
}
+
+ if (cache) {
+ hdr.flags |= SD_FLAG_CMD_CACHE;
+ }
+
hdr.oid = oid;
hdr.data_length = datalen;
hdr.offset = offset;
@@ -986,15 +1050,18 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
}
static int read_object(int fd, char *buf, uint64_t oid, int copies,
- unsigned int datalen, uint64_t offset)
+ unsigned int datalen, uint64_t offset, uint8_t cache)
{
- return read_write_object(fd, buf, oid, copies, datalen, offset, 0, 0);
+ return read_write_object(fd, buf, oid, copies, datalen, offset, 0, 0,
+ cache);
}
static int write_object(int fd, char *buf, uint64_t oid, int copies,
- unsigned int datalen, uint64_t offset, int create)
+ unsigned int datalen, uint64_t offset, int create,
+ uint8_t cache)
{
- return read_write_object(fd, buf, oid, copies, datalen, offset, 1, create);
+ return read_write_object(fd, buf, oid, copies, datalen, offset, 1, create,
+ cache);
}
static int sd_open(BlockDriverState *bs, const char *filename, int flags)
@@ -1026,6 +1093,15 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
goto out;
}
+ if (flags & BDRV_O_CACHE_WB) {
+ s->cache_enabled = 1;
+ s->flush_fd = connect_to_sdog(s->addr, s->port);
+ if (s->flush_fd < 0) {
+ error_report("failed to connect");
+ goto out;
+ }
+ }
+
if (snapid) {
dprintf("%" PRIx32 " snapshot inode was open.\n", vid);
s->is_snapshot = 1;
@@ -1038,7 +1114,8 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
}
buf = g_malloc(SD_INODE_SIZE);
- ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0);
+ ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0,
+ s->cache_enabled);
closesocket(fd);
@@ -1272,6 +1349,9 @@ static void sd_close(BlockDriverState *bs)
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
closesocket(s->fd);
+ if (s->cache_enabled) {
+ closesocket(s->flush_fd);
+ }
g_free(s->addr);
}
@@ -1305,7 +1385,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
s->inode.vdi_size = offset;
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
- s->inode.nr_copies, datalen, 0, 0);
+ s->inode.nr_copies, datalen, 0, 0, s->cache_enabled);
close(fd);
if (ret < 0) {
@@ -1387,7 +1467,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
}
ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
- SD_INODE_SIZE, 0);
+ SD_INODE_SIZE, 0, s->cache_enabled);
closesocket(fd);
@@ -1575,6 +1655,36 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
return acb->ret;
}
+static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
+{
+ BDRVSheepdogState *s = bs->opaque;
+ SheepdogObjReq hdr = { 0 };
+ SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr;
+ SheepdogInode *inode = &s->inode;
+ int ret;
+ unsigned int wlen = 0, rlen = 0;
+
+ if (!s->cache_enabled) {
+ return 0;
+ }
+
+ hdr.opcode = SD_OP_FLUSH_VDI;
+ hdr.oid = vid_to_vdi_oid(inode->vdi_id);
+
+ ret = do_co_req(s->flush_fd, (SheepdogReq *)&hdr, NULL, &wlen, &rlen);
+ if (ret) {
+ error_report("failed to send a request to the sheep");
+ return ret;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ error_report("%s", sd_strerror(rsp->result));
+ return -EIO;
+ }
+
+ return 0;
+}
+
static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
{
BDRVSheepdogState *s = bs->opaque;
@@ -1610,7 +1720,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
}
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
- s->inode.nr_copies, datalen, 0, 0);
+ s->inode.nr_copies, datalen, 0, 0, s->cache_enabled);
if (ret < 0) {
error_report("failed to write snapshot's inode.");
ret = -EIO;
@@ -1629,7 +1739,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
inode = (SheepdogInode *)g_malloc(datalen);
ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
- s->inode.nr_copies, datalen, 0);
+ s->inode.nr_copies, datalen, 0, s->cache_enabled);
if (ret < 0) {
error_report("failed to read new inode info. %s", strerror(errno));
@@ -1684,7 +1794,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
buf = g_malloc(SD_INODE_SIZE);
ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
- SD_INODE_SIZE, 0);
+ SD_INODE_SIZE, 0, s->cache_enabled);
closesocket(fd);
@@ -1779,7 +1889,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
/* we don't need to read entire object */
ret = read_object(fd, (char *)&inode, vid_to_vdi_oid(vid),
- 0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0);
+ 0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0,
+ s->cache_enabled);
if (ret) {
continue;
@@ -1835,10 +1946,12 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
create = (offset == 0);
if (load) {
ret = read_object(fd, (char *)data, vmstate_oid,
- s->inode.nr_copies, data_len, offset);
+ s->inode.nr_copies, data_len, offset,
+ s->cache_enabled);
} else {
ret = write_object(fd, (char *)data, vmstate_oid,
- s->inode.nr_copies, data_len, offset, create);
+ s->inode.nr_copies, data_len, offset, create,
+ s->cache_enabled);
}
if (ret < 0) {
@@ -1904,6 +2017,7 @@ BlockDriver bdrv_sheepdog = {
.bdrv_co_readv = sd_co_readv,
.bdrv_co_writev = sd_co_writev,
+ .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
.bdrv_snapshot_create = sd_snapshot_create,
.bdrv_snapshot_goto = sd_snapshot_goto,
commit f6801b83d0e77ca025867800d805ee80f6bda938
Author: Jeff Cody <jcody at redhat.com>
Date: Tue Mar 27 16:30:19 2012 -0400
block: bdrv_append() fixes
A few fixups for bdrv_append():
The new bs (bs_new) passed into bdrv_append() should be anonymous. Rather
than call bdrv_make_anon() to enforce this, use an assert to catch when a caller
is passing in a bs_new that is not anonymous.
Also, the new top layer should have its backing_format reflect the original
top's format.
And last, after the swap of bs contents, the device_name will have been copied
down. This needs to be cleared to reflect the anonymity of the bs that was
pushed down.
Signed-off-by: Jeff Cody <jcody at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index 33630eb..b3117ef 100644
--- a/block.c
+++ b/block.c
@@ -892,14 +892,16 @@ void bdrv_make_anon(BlockDriverState *bs)
* This will modify the BlockDriverState fields, and swap contents
* between bs_new and bs_top. Both bs_new and bs_top are modified.
*
+ * bs_new is required to be anonymous.
+ *
* This function does not create any image files.
*/
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
{
BlockDriverState tmp;
- /* the new bs must not be in bdrv_states */
- bdrv_make_anon(bs_new);
+ /* bs_new must be anonymous */
+ assert(bs_new->device_name[0] == '\0');
tmp = *bs_new;
@@ -944,11 +946,18 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
* swapping bs_new and bs_top contents. */
tmp.backing_hd = bs_new;
pstrcpy(tmp.backing_file, sizeof(tmp.backing_file), bs_top->filename);
+ bdrv_get_format(bs_top, tmp.backing_format, sizeof(tmp.backing_format));
/* swap contents of the fixed new bs and the current top */
*bs_new = *bs_top;
*bs_top = tmp;
+ /* device_name[] was carried over from the old bs_top. bs_new
+ * shouldn't be in bdrv_states, so we need to make device_name[]
+ * reflect the anonymity of bs_new
+ */
+ bs_new->device_name[0] = '\0';
+
/* clear the copied fields in the new backing file */
bdrv_detach_dev(bs_new, bs_new->dev);
commit d68dbee80e3964d9bb0ab29ad64675da148c3cac
Author: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Date: Thu Mar 15 20:13:34 2012 +0800
qed: track dirty flag status
Signed-off-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qed.c b/block/qed.c
index d6c1580..19d87f3 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1434,6 +1434,7 @@ static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
memset(bdi, 0, sizeof(*bdi));
bdi->cluster_size = s->header.cluster_size;
+ bdi->is_dirty = s->header.features & QED_F_NEED_CHECK;
return 0;
}
commit 64c79160b456c2d6aabc63e40b32e392a9ea3c90
Author: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Date: Thu Mar 15 20:13:33 2012 +0800
qemu-img: add dirty flag status
Some block drivers can verify their image files are clean or not. So we can show
it while using "qemu-img info".
Signed-off-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.h b/block.h
index ea12f5d..4e99e18 100644
--- a/block.h
+++ b/block.h
@@ -15,6 +15,7 @@ typedef struct BlockDriverInfo {
int cluster_size;
/* offset at which the VM state can be saved (0 if not possible) */
int64_t vm_state_offset;
+ bool is_dirty;
} BlockDriverInfo;
typedef struct BlockFragInfo {
diff --git a/qemu-img.c b/qemu-img.c
index 4de48ba..6a61ca8 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1132,6 +1132,9 @@ static int img_info(int argc, char **argv)
if (bdi.cluster_size != 0) {
printf("cluster_size: %d\n", bdi.cluster_size);
}
+ if (bdi.is_dirty) {
+ printf("cleanly shut down: no\n");
+ }
}
bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
if (backing_filename[0] != '\0') {
commit 11c9c615c8e776e59ad0c6c6ed00ec7d38b5d865
Author: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Date: Thu Mar 15 20:13:32 2012 +0800
qed: image fragmentation statistics
Signed-off-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qed-check.c b/block/qed-check.c
index e4a49ce..94327ff 100644
--- a/block/qed-check.c
+++ b/block/qed-check.c
@@ -68,6 +68,7 @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
{
BDRVQEDState *s = check->s;
unsigned int i, num_invalid = 0;
+ uint64_t last_offset = 0;
for (i = 0; i < s->table_nelems; i++) {
uint64_t offset = table->offsets[i];
@@ -76,6 +77,11 @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
qed_offset_is_zero_cluster(offset)) {
continue;
}
+ check->result->bfi.allocated_clusters++;
+ if (last_offset && (last_offset + s->header.cluster_size != offset)) {
+ check->result->bfi.fragmented_clusters++;
+ }
+ last_offset = offset;
/* Detect invalid cluster offset */
if (!qed_check_cluster_offset(s, offset)) {
@@ -200,6 +206,9 @@ int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
check.used_clusters = g_malloc0(((check.nclusters + 31) / 32) *
sizeof(check.used_clusters[0]));
+ check.result->bfi.total_clusters =
+ (s->header.image_size + s->header.cluster_size - 1) /
+ s->header.cluster_size;
ret = qed_check_l1_table(&check, s->l1_table);
if (ret == 0) {
/* Only check for leaks if entire image was scanned successfully */
commit f8111c241afa75544032dcfa23df0699c91f9866
Author: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Date: Thu Mar 15 20:13:31 2012 +0800
qemu-img: add image fragmentation statistics
Discussion can be found at:
http://patchwork.ozlabs.org/patch/128730/
This patch add image fragmentation statistics while using qemu-img check.
Signed-off-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.h b/block.h
index c51ab16..ea12f5d 100644
--- a/block.h
+++ b/block.h
@@ -17,6 +17,12 @@ typedef struct BlockDriverInfo {
int64_t vm_state_offset;
} BlockDriverInfo;
+typedef struct BlockFragInfo {
+ uint64_t allocated_clusters;
+ uint64_t total_clusters;
+ uint64_t fragmented_clusters;
+} BlockFragInfo;
+
typedef struct QEMUSnapshotInfo {
char id_str[128]; /* unique snapshot id */
/* the following fields are informative. They are not needed for
@@ -175,6 +181,7 @@ typedef struct BdrvCheckResult {
int corruptions;
int leaks;
int check_errors;
+ BlockFragInfo bfi;
} BdrvCheckResult;
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res);
diff --git a/qemu-img.c b/qemu-img.c
index 0e48b35..4de48ba 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -428,6 +428,13 @@ static int img_check(int argc, char **argv)
}
}
+ if (result.bfi.total_clusters != 0 && result.bfi.allocated_clusters != 0) {
+ printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n",
+ result.bfi.allocated_clusters, result.bfi.total_clusters,
+ result.bfi.allocated_clusters * 100.0 / result.bfi.total_clusters,
+ result.bfi.fragmented_clusters * 100.0 / result.bfi.allocated_clusters);
+ }
+
bdrv_delete(bs);
if (ret < 0 || result.check_errors) {
@@ -716,7 +723,7 @@ static int img_convert(int argc, char **argv)
ret = -1;
goto out;
}
-
+
qemu_progress_init(progress, 2.0);
qemu_progress_print(0, 100);
commit dc534f8fc045a51a8eb678ab3d330fba1e9e631c
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 13:17:13 2012 +0200
block: document job API
I am not sure that these are really proper GtkDoc, but they follow
the existing documentation in block_int.h.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block_int.h b/block_int.h
index a96aabd..0e5a032 100644
--- a/block_int.h
+++ b/block_int.h
@@ -63,8 +63,13 @@ typedef struct BlockIOBaseValue {
uint64_t ios[2];
} BlockIOBaseValue;
-typedef void BlockJobCancelFunc(void *opaque);
typedef struct BlockJob BlockJob;
+
+/**
+ * BlockJobType:
+ *
+ * A class type for block job objects.
+ */
typedef struct BlockJobType {
/** Derived BlockJob struct size */
size_t instance_size;
@@ -77,20 +82,48 @@ typedef struct BlockJobType {
} BlockJobType;
/**
- * Long-running operation on a BlockDriverState
+ * BlockJob:
+ *
+ * Long-running operation on a BlockDriverState.
*/
struct BlockJob {
+ /** The job type, including the job vtable. */
const BlockJobType *job_type;
+
+ /** The block device on which the job is operating. */
BlockDriverState *bs;
+
+ /**
+ * Set to true if the job should cancel itself. The flag must
+ * always be tested just before toggling the busy flag from false
+ * to true. After a job has detected that the cancelled flag is
+ * true, it should not anymore issue any I/O operation to the
+ * block device.
+ */
bool cancelled;
+
+ /**
+ * Set to false by the job while it is in a quiescent state, where
+ * no I/O is pending and cancellation can be processed without
+ * issuing new I/O. The busy flag must be set to false when the
+ * job goes to sleep on any condition that is not detected by
+ * #qemu_aio_wait, such as a timer.
+ */
bool busy;
- /* These fields are published by the query-block-jobs QMP API */
+ /** Offset that is published by the query-block-jobs QMP API */
int64_t offset;
+
+ /** Length that is published by the query-block-jobs QMP API */
int64_t len;
+
+ /** Speed that was set with @block_job_set_speed. */
int64_t speed;
+ /** The completion function that will be called when the job completes. */
BlockDriverCompletionFunc *cb;
+
+ /** The opaque value that is passed to the completion function. */
void *opaque;
};
@@ -306,14 +339,90 @@ void bdrv_set_io_limits(BlockDriverState *bs,
int is_windows_drive(const char *filename);
#endif
+/**
+ * block_job_create:
+ * @job_type: The class object for the newly-created job.
+ * @bs: The block
+ * @cb: Completion function for the job.
+ * @opaque: Opaque pointer value passed to @cb.
+ *
+ * Create a new long-running block device job and return it. The job
+ * will call @cb asynchronously when the job completes. Note that
+ * @bs may have been closed at the time the @cb it is called. If
+ * this is the case, the job may be reported as either cancelled or
+ * completed.
+ *
+ * This function is not part of the public job interface; it should be
+ * called from a wrapper that is specific to the job type.
+ */
void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
+
+/**
+ * block_job_complete:
+ * @job: The job being completed.
+ * @ret: The status code.
+ *
+ * Call the completion function that was registered at creation time, and
+ * free @job.
+ */
void block_job_complete(BlockJob *job, int ret);
+
+/**
+ * block_job_set_speed:
+ * @job: The job to set the speed for.
+ * @speed: The new value
+ *
+ * Set a rate-limiting parameter for the job; the actual meaning may
+ * vary depending on the job type.
+ */
int block_job_set_speed(BlockJob *job, int64_t value);
+
+/**
+ * block_job_cancel:
+ * @job: The job to be canceled.
+ *
+ * Asynchronously cancel the specified job.
+ */
void block_job_cancel(BlockJob *job);
+
+/**
+ * block_job_is_cancelled:
+ * @job: The job being queried.
+ *
+ * Returns whether the job is scheduled for cancellation.
+ */
bool block_job_is_cancelled(BlockJob *job);
+
+/**
+ * block_job_cancel:
+ * @job: The job to be canceled.
+ *
+ * Asynchronously cancel the job and wait for it to reach a quiescent
+ * state. Note that the completion callback will still be called
+ * asynchronously, hence it is *not* valid to call #bdrv_delete
+ * immediately after #block_job_cancel_sync. Users of block jobs
+ * will usually protect the BlockDriverState objects with a reference
+ * count, should this be a concern.
+ */
void block_job_cancel_sync(BlockJob *job);
+/**
+ * stream_start:
+ * @bs: Block device to operate on.
+ * @base: Block device that will become the new base, or %NULL to
+ * flatten the whole backing file chain onto @bs.
+ * @base_id: The file name that will be written to @bs as the new
+ * backing file if the job completes. Ignored if @base is %NULL.
+ * @cb: Completion function for the job.
+ * @opaque: Opaque pointer value passed to @cb.
+ *
+ * Start a streaming operation on @bs. Clusters that are unallocated
+ * in @bs, but allocated in any image between @base and @bs (both
+ * exclusive) will be written to @bs. At the end of a successful
+ * streaming job, the backing file of @bs will be changed to
+ * @base_id in the written image and to @base in the live BlockDriverState.
+ */
int stream_start(BlockDriverState *bs, BlockDriverState *base,
const char *base_id, BlockDriverCompletionFunc *cb,
void *opaque);
commit 9f25eccc1cdbe6ee985b7a5954fa621c2012912e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 13:17:12 2012 +0200
block: set job->speed in block_set_speed
There is no need to do this in every implementation of set_speed
(even though there is only one right now).
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index 16e14fa..33630eb 100644
--- a/block.c
+++ b/block.c
@@ -4085,10 +4085,16 @@ void block_job_complete(BlockJob *job, int ret)
int block_job_set_speed(BlockJob *job, int64_t value)
{
+ int rc;
+
if (!job->job_type->set_speed) {
return -ENOTSUP;
}
- return job->job_type->set_speed(job, value);
+ rc = job->job_type->set_speed(job, value);
+ if (rc == 0) {
+ job->speed = value;
+ }
+ return rc;
}
void block_job_cancel(BlockJob *job)
diff --git a/block/stream.c b/block/stream.c
index f186bfd..61ff7a2 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -236,7 +236,6 @@ static int stream_set_speed(BlockJob *job, int64_t value)
if (value < 0) {
return -EINVAL;
}
- job->speed = value;
ratelimit_set_speed(&s->limit, value / BDRV_SECTOR_SIZE);
return 0;
}
commit 3e914655f268f627ef004a8f1ea0355311b5aca6
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 13:17:11 2012 +0200
block: fix streaming/closing race
Streaming can issue I/O while qcow2_close is running. This causes the
L2 caches to become very confused or, alternatively, could cause a
segfault when the streaming coroutine is reentered after closing its
block device. The fix is to cancel streaming jobs when closing their
underlying device.
The cancellation must be synchronous, on the other hand qemu_aio_wait
will not restart a coroutine that is sleeping in co_sleep. So add
a flag saying whether streaming has in-flight I/O. If the busy flag
is false, the coroutine is quiescent and, when cancelled, will not
issue any new I/O.
This protects streaming against closing, but not against deleting.
We have a reference count protecting us against concurrent deletion,
but I still added an assertion to ensure nothing bad happens.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index 0344673..16e14fa 100644
--- a/block.c
+++ b/block.c
@@ -813,6 +813,9 @@ unlink_and_fail:
void bdrv_close(BlockDriverState *bs)
{
if (bs->drv) {
+ if (bs->job) {
+ block_job_cancel_sync(bs->job);
+ }
if (bs == bs_snapshots) {
bs_snapshots = NULL;
}
@@ -966,6 +969,8 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->dev);
+ assert(!bs->job);
+ assert(!bs->in_use);
/* remove from list, if necessary */
bdrv_make_anon(bs);
@@ -4095,3 +4100,14 @@ bool block_job_is_cancelled(BlockJob *job)
{
return job->cancelled;
}
+
+void block_job_cancel_sync(BlockJob *job)
+{
+ BlockDriverState *bs = job->bs;
+
+ assert(bs->job == job);
+ block_job_cancel(job);
+ while (bs->job != NULL && bs->job->busy) {
+ qemu_aio_wait();
+ }
+}
diff --git a/block/stream.c b/block/stream.c
index d1b3986..f186bfd 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -175,7 +175,7 @@ retry:
break;
}
-
+ s->common.busy = true;
if (base) {
ret = is_allocated_base(bs, base, sector_num,
STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
@@ -189,6 +189,7 @@ retry:
if (s->common.speed) {
uint64_t delay_ns = ratelimit_calculate_delay(&s->limit, n);
if (delay_ns > 0) {
+ s->common.busy = false;
co_sleep_ns(rt_clock, delay_ns);
/* Recheck cancellation and that sectors are unallocated */
@@ -208,6 +209,7 @@ retry:
/* Note that even when no rate limit is applied we need to yield
* with no pending I/O here so that qemu_aio_flush() returns.
*/
+ s->common.busy = false;
co_sleep_ns(rt_clock, 0);
}
@@ -215,7 +217,7 @@ retry:
bdrv_disable_copy_on_read(bs);
}
- if (sector_num == end && ret == 0) {
+ if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) {
const char *base_id = NULL;
if (base) {
base_id = s->backing_file_id;
diff --git a/block_int.h b/block_int.h
index 22c86a5..a96aabd 100644
--- a/block_int.h
+++ b/block_int.h
@@ -83,6 +83,7 @@ struct BlockJob {
const BlockJobType *job_type;
BlockDriverState *bs;
bool cancelled;
+ bool busy;
/* These fields are published by the query-block-jobs QMP API */
int64_t offset;
@@ -311,6 +312,7 @@ void block_job_complete(BlockJob *job, int ret);
int block_job_set_speed(BlockJob *job, int64_t value);
void block_job_cancel(BlockJob *job);
bool block_job_is_cancelled(BlockJob *job);
+void block_job_cancel_sync(BlockJob *job);
int stream_start(BlockDriverState *bs, BlockDriverState *base,
const char *base_id, BlockDriverCompletionFunc *cb,
commit 12bde0eed6b740787bca2c998a838b20c556d0ec
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 13:17:10 2012 +0200
block: cancel jobs when a device is ready to go away
We do not want jobs to keep a device busy for a possibly very long
time, and management could become confused because they thought a
device was not even there anymore. So, cancel long-running jobs
as soon as their device is going to disappear.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/blockdev.c b/blockdev.c
index f5e7dba..4d17486 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -64,6 +64,9 @@ void blockdev_mark_auto_del(BlockDriverState *bs)
{
DriveInfo *dinfo = drive_get_by_blockdev(bs);
+ if (bs->job) {
+ block_job_cancel(bs->job);
+ }
if (dinfo) {
dinfo->auto_del = 1;
}
commit 498e386c58497f621a37301ea6e8ca886f9f2e07
Author: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
Date: Mon Apr 2 18:59:34 2012 +0800
block: disable I/O throttling on sync api
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index 8858be0..0344673 100644
--- a/block.c
+++ b/block.c
@@ -1463,6 +1463,17 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
qemu_iovec_init_external(&qiov, &iov, 1);
+ /**
+ * In sync call context, when the vcpu is blocked, this throttling timer
+ * will not fire; so the I/O throttling function has to be disabled here
+ * if it has been enabled.
+ */
+ if (bs->io_limits_enabled) {
+ fprintf(stderr, "Disabling I/O throttling on '%s' due "
+ "to synchronous I/O.\n", bdrv_get_device_name(bs));
+ bdrv_io_limits_disable(bs);
+ }
+
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_rw_co_entry(&rwco);
@@ -1969,10 +1980,19 @@ static int guess_disk_lchs(BlockDriverState *bs,
struct partition *p;
uint32_t nr_sects;
uint64_t nb_sectors;
+ bool enabled;
bdrv_get_geometry(bs, &nb_sectors);
+ /**
+ * The function will be invoked during startup not only in sync I/O mode,
+ * but also in async I/O mode. So the I/O throttling function has to
+ * be disabled temporarily here, not permanently.
+ */
+ enabled = bs->io_limits_enabled;
+ bs->io_limits_enabled = false;
ret = bdrv_read(bs, 0, buf, 1);
+ bs->io_limits_enabled = enabled;
if (ret < 0)
return -1;
/* test msdos magic */
commit 43cf8ae69ba8510e45d7bd42dd67bc8ae13c48ec
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Tue Mar 27 13:42:23 2012 +1100
Use DMADirection type for dma_bdrv_io
Currently dma_bdrv_io() takes a 'to_dev' boolean parameter to
determine the direction of DMA it is emulating. We already have a
DMADirection enum designed specifically to encode DMA directions.
This patch uses it for dma_bdrv_io() as well. This involves removing
the DMADirection definition from the #ifdef it was inside, but since that
only existed to protect the definition of dma_addr_t from places where
config.h is not included, there wasn't any reason for it to be there in
the first place.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/dma-helpers.c b/dma-helpers.c
index 7fcc86d..7971a89 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -41,7 +41,7 @@ typedef struct {
BlockDriverAIOCB *acb;
QEMUSGList *sg;
uint64_t sector_num;
- bool to_dev;
+ DMADirection dir;
bool in_cancel;
int sg_cur_index;
dma_addr_t sg_cur_byte;
@@ -75,7 +75,8 @@ static void dma_bdrv_unmap(DMAAIOCB *dbs)
for (i = 0; i < dbs->iov.niov; ++i) {
cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base,
- dbs->iov.iov[i].iov_len, !dbs->to_dev,
+ dbs->iov.iov[i].iov_len,
+ dbs->dir != DMA_DIRECTION_TO_DEVICE,
dbs->iov.iov[i].iov_len);
}
qemu_iovec_reset(&dbs->iov);
@@ -122,7 +123,8 @@ static void dma_bdrv_cb(void *opaque, int ret)
while (dbs->sg_cur_index < dbs->sg->nsg) {
cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
- mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->to_dev);
+ mem = cpu_physical_memory_map(cur_addr, &cur_len,
+ dbs->dir != DMA_DIRECTION_TO_DEVICE);
if (!mem)
break;
qemu_iovec_add(&dbs->iov, mem, cur_len);
@@ -169,11 +171,11 @@ static AIOPool dma_aio_pool = {
BlockDriverAIOCB *dma_bdrv_io(
BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
- void *opaque, bool to_dev)
+ void *opaque, DMADirection dir)
{
DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
- trace_dma_bdrv_io(dbs, bs, sector_num, to_dev);
+ trace_dma_bdrv_io(dbs, bs, sector_num, (dir == DMA_DIRECTION_TO_DEVICE));
dbs->acb = NULL;
dbs->bs = bs;
@@ -181,7 +183,7 @@ BlockDriverAIOCB *dma_bdrv_io(
dbs->sector_num = sector_num;
dbs->sg_cur_index = 0;
dbs->sg_cur_byte = 0;
- dbs->to_dev = to_dev;
+ dbs->dir = dir;
dbs->io_func = io_func;
dbs->bh = NULL;
qemu_iovec_init(&dbs->iov, sg->nsg);
@@ -194,14 +196,16 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
{
- return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, false);
+ return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque,
+ DMA_DIRECTION_FROM_DEVICE);
}
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
{
- return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, true);
+ return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque,
+ DMA_DIRECTION_TO_DEVICE);
}
diff --git a/dma.h b/dma.h
index 20e86d2..05ac325 100644
--- a/dma.h
+++ b/dma.h
@@ -17,6 +17,11 @@
typedef struct ScatterGatherEntry ScatterGatherEntry;
+typedef enum {
+ DMA_DIRECTION_TO_DEVICE = 0,
+ DMA_DIRECTION_FROM_DEVICE = 1,
+} DMADirection;
+
struct QEMUSGList {
ScatterGatherEntry *sg;
int nsg;
@@ -29,11 +34,6 @@ typedef target_phys_addr_t dma_addr_t;
#define DMA_ADDR_FMT TARGET_FMT_plx
-typedef enum {
- DMA_DIRECTION_TO_DEVICE = 0,
- DMA_DIRECTION_FROM_DEVICE = 1,
-} DMADirection;
-
struct ScatterGatherEntry {
dma_addr_t base;
dma_addr_t len;
@@ -51,7 +51,7 @@ typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector_num,
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
- void *opaque, bool to_dev);
+ void *opaque, DMADirection dir);
BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
BlockDriverCompletionFunc *cb, void *opaque);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 6e25338..35723fd 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -618,7 +618,8 @@ void ide_dma_cb(void *opaque, int ret)
break;
case IDE_DMA_TRIM:
s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
- ide_issue_trim, ide_dma_cb, s, true);
+ ide_issue_trim, ide_dma_cb, s,
+ DMA_DIRECTION_TO_DEVICE);
break;
}
return;
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index a4df244..7b38d9e 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -149,7 +149,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
break;
case IDE_DMA_TRIM:
m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
- ide_issue_trim, pmac_ide_transfer_cb, s, true);
+ ide_issue_trim, pmac_ide_transfer_cb, s,
+ DMA_DIRECTION_TO_DEVICE);
break;
}
return;
commit eb9566d13e30dd7e20d978632a13915cbdb9a668
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 19 18:07:51 2012 +0100
vdi: change goto to loop
Finally reindent all code and change goto statements to a loop.
Acked-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vdi.c b/block/vdi.c
index bfeafea..119d3c7 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -474,41 +474,38 @@ static int vdi_co_read(BlockDriverState *bs,
uint32_t block_index;
uint32_t sector_in_block;
uint32_t n_sectors;
- int ret;
+ int ret = 0;
logout("\n");
-restart:
- block_index = sector_num / s->block_sectors;
- sector_in_block = sector_num % s->block_sectors;
- n_sectors = s->block_sectors - sector_in_block;
- if (n_sectors > nb_sectors) {
- n_sectors = nb_sectors;
- }
-
- logout("will read %u sectors starting at sector %" PRIu64 "\n",
- n_sectors, sector_num);
+ while (ret >= 0 && nb_sectors > 0) {
+ block_index = sector_num / s->block_sectors;
+ sector_in_block = sector_num % s->block_sectors;
+ n_sectors = s->block_sectors - sector_in_block;
+ if (n_sectors > nb_sectors) {
+ n_sectors = nb_sectors;
+ }
- /* prepare next AIO request */
- bmap_entry = le32_to_cpu(s->bmap[block_index]);
- if (!VDI_IS_ALLOCATED(bmap_entry)) {
- /* Block not allocated, return zeros, no need to wait. */
- memset(buf, 0, n_sectors * SECTOR_SIZE);
- ret = 0;
- } else {
- uint64_t offset = s->header.offset_data / SECTOR_SIZE +
- (uint64_t)bmap_entry * s->block_sectors +
- sector_in_block;
- ret = bdrv_read(bs->file, offset, buf, n_sectors);
- }
- logout("%u sectors read\n", n_sectors);
+ logout("will read %u sectors starting at sector %" PRIu64 "\n",
+ n_sectors, sector_num);
- nb_sectors -= n_sectors;
- sector_num += n_sectors;
- buf += n_sectors * SECTOR_SIZE;
+ /* prepare next AIO request */
+ bmap_entry = le32_to_cpu(s->bmap[block_index]);
+ if (!VDI_IS_ALLOCATED(bmap_entry)) {
+ /* Block not allocated, return zeros, no need to wait. */
+ memset(buf, 0, n_sectors * SECTOR_SIZE);
+ ret = 0;
+ } else {
+ uint64_t offset = s->header.offset_data / SECTOR_SIZE +
+ (uint64_t)bmap_entry * s->block_sectors +
+ sector_in_block;
+ ret = bdrv_read(bs->file, offset, buf, n_sectors);
+ }
+ logout("%u sectors read\n", n_sectors);
- if (ret >= 0 && nb_sectors > 0) {
- goto restart;
+ nb_sectors -= n_sectors;
+ sector_num += n_sectors;
+ buf += n_sectors * SECTOR_SIZE;
}
return ret;
@@ -525,57 +522,55 @@ static int vdi_co_write(BlockDriverState *bs,
uint32_t bmap_first = VDI_UNALLOCATED;
uint32_t bmap_last = VDI_UNALLOCATED;
uint8_t *block = NULL;
- int ret;
+ int ret = 0;
logout("\n");
-restart:
- block_index = sector_num / s->block_sectors;
- sector_in_block = sector_num % s->block_sectors;
- n_sectors = s->block_sectors - sector_in_block;
- if (n_sectors > nb_sectors) {
- n_sectors = nb_sectors;
- }
-
- logout("will write %u sectors starting at sector %" PRIu64 "\n",
- n_sectors, sector_num);
+ while (ret >= 0 && nb_sectors > 0) {
+ block_index = sector_num / s->block_sectors;
+ sector_in_block = sector_num % s->block_sectors;
+ n_sectors = s->block_sectors - sector_in_block;
+ if (n_sectors > nb_sectors) {
+ n_sectors = nb_sectors;
+ }
- /* prepare next AIO request */
- bmap_entry = le32_to_cpu(s->bmap[block_index]);
- if (!VDI_IS_ALLOCATED(bmap_entry)) {
- /* Allocate new block and write to it. */
- uint64_t offset;
- bmap_entry = s->header.blocks_allocated;
- s->bmap[block_index] = cpu_to_le32(bmap_entry);
- s->header.blocks_allocated++;
- offset = s->header.offset_data / SECTOR_SIZE +
- (uint64_t)bmap_entry * s->block_sectors;
- if (block == NULL) {
- block = g_malloc(s->block_size);
- bmap_first = block_index;
+ logout("will write %u sectors starting at sector %" PRIu64 "\n",
+ n_sectors, sector_num);
+
+ /* prepare next AIO request */
+ bmap_entry = le32_to_cpu(s->bmap[block_index]);
+ if (!VDI_IS_ALLOCATED(bmap_entry)) {
+ /* Allocate new block and write to it. */
+ uint64_t offset;
+ bmap_entry = s->header.blocks_allocated;
+ s->bmap[block_index] = cpu_to_le32(bmap_entry);
+ s->header.blocks_allocated++;
+ offset = s->header.offset_data / SECTOR_SIZE +
+ (uint64_t)bmap_entry * s->block_sectors;
+ if (block == NULL) {
+ block = g_malloc(s->block_size);
+ bmap_first = block_index;
+ }
+ bmap_last = block_index;
+ /* Copy data to be written to new block and zero unused parts. */
+ memset(block, 0, sector_in_block * SECTOR_SIZE);
+ memcpy(block + sector_in_block * SECTOR_SIZE,
+ buf, n_sectors * SECTOR_SIZE);
+ memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
+ (s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
+ ret = bdrv_write(bs->file, offset, block, s->block_sectors);
+ } else {
+ uint64_t offset = s->header.offset_data / SECTOR_SIZE +
+ (uint64_t)bmap_entry * s->block_sectors +
+ sector_in_block;
+ ret = bdrv_write(bs->file, offset, buf, n_sectors);
}
- bmap_last = block_index;
- /* Copy data to be written to new block and zero unused parts. */
- memset(block, 0, sector_in_block * SECTOR_SIZE);
- memcpy(block + sector_in_block * SECTOR_SIZE,
- buf, n_sectors * SECTOR_SIZE);
- memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
- (s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
- ret = bdrv_write(bs->file, offset, block, s->block_sectors);
- } else {
- uint64_t offset = s->header.offset_data / SECTOR_SIZE +
- (uint64_t)bmap_entry * s->block_sectors +
- sector_in_block;
- ret = bdrv_write(bs->file, offset, buf, n_sectors);
- }
- nb_sectors -= n_sectors;
- sector_num += n_sectors;
- buf += n_sectors * SECTOR_SIZE;
+ nb_sectors -= n_sectors;
+ sector_num += n_sectors;
+ buf += n_sectors * SECTOR_SIZE;
- logout("%u sectors written\n", n_sectors);
- if (ret >= 0 && nb_sectors > 0) {
- goto restart;
+ logout("%u sectors written\n", n_sectors);
}
logout("finished data write\n");
commit 4eea78e6345518bfe87493d8b163e1e268e64f74
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 19 18:07:50 2012 +0100
vdi: do not create useless iovecs
Reads and writes to the underlying file can also occur with the simple
non-vectored I/O interfaces.
Acked-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vdi.c b/block/vdi.c
index 790b61e..bfeafea 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -474,8 +474,6 @@ static int vdi_co_read(BlockDriverState *bs,
uint32_t block_index;
uint32_t sector_in_block;
uint32_t n_sectors;
- struct iovec hd_iov;
- QEMUIOVector hd_qiov;
int ret;
logout("\n");
@@ -501,10 +499,7 @@ restart:
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
- hd_iov.iov_base = (void *)buf;
- hd_iov.iov_len = n_sectors * SECTOR_SIZE;
- qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
- ret = bdrv_co_readv(bs->file, offset, n_sectors, &hd_qiov);
+ ret = bdrv_read(bs->file, offset, buf, n_sectors);
}
logout("%u sectors read\n", n_sectors);
@@ -529,8 +524,6 @@ static int vdi_co_write(BlockDriverState *bs,
uint32_t n_sectors;
uint32_t bmap_first = VDI_UNALLOCATED;
uint32_t bmap_last = VDI_UNALLOCATED;
- struct iovec hd_iov;
- QEMUIOVector hd_qiov;
uint8_t *block = NULL;
int ret;
@@ -568,18 +561,12 @@ restart:
buf, n_sectors * SECTOR_SIZE);
memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
(s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
- hd_iov.iov_base = (void *)block;
- hd_iov.iov_len = s->block_size;
- qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
- ret = bdrv_co_writev(bs->file, offset, s->block_sectors, &hd_qiov);
+ ret = bdrv_write(bs->file, offset, block, s->block_sectors);
} else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
- hd_iov.iov_base = (void *)buf;
- hd_iov.iov_len = n_sectors * SECTOR_SIZE;
- qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
- ret = bdrv_co_writev(bs->file, offset, n_sectors, &hd_qiov);
+ ret = bdrv_write(bs->file, offset, buf, n_sectors);
}
nb_sectors -= n_sectors;
@@ -592,39 +579,39 @@ restart:
}
logout("finished data write\n");
- if (ret >= 0) {
- ret = 0;
- if (block) {
- VdiHeader *header = (VdiHeader *) block;
- logout("now writing modified header\n");
- assert(VDI_IS_ALLOCATED(bmap_first));
- *header = s->header;
- vdi_header_to_le(header);
- hd_iov.iov_base = block;
- hd_iov.iov_len = SECTOR_SIZE;
- qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
- ret = bdrv_co_writev(bs->file, 0, 1, &hd_qiov);
- }
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (block) {
+ /* One or more new blocks were allocated. */
+ VdiHeader *header = (VdiHeader *) block;
+ uint8_t *base;
+ uint64_t offset;
+
+ logout("now writing modified header\n");
+ assert(VDI_IS_ALLOCATED(bmap_first));
+ *header = s->header;
+ vdi_header_to_le(header);
+ ret = bdrv_write(bs->file, 0, block, 1);
g_free(block);
block = NULL;
- if (ret >= 0 && VDI_IS_ALLOCATED(bmap_first)) {
- /* One or more new blocks were allocated. */
- uint64_t offset;
- logout("now writing modified block map entry %u...%u\n",
- bmap_first, bmap_last);
- /* Write modified sectors from block map. */
- bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
- bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
- n_sectors = bmap_last - bmap_first + 1;
- offset = s->bmap_sector + bmap_first;
- hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
- bmap_first * SECTOR_SIZE);
- hd_iov.iov_len = n_sectors * SECTOR_SIZE;
- qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
- logout("will write %u block map sectors starting from entry %u\n",
- n_sectors, bmap_first);
- ret = bdrv_co_writev(bs->file, offset, n_sectors, &hd_qiov);
+
+ if (ret < 0) {
+ return ret;
}
+
+ logout("now writing modified block map entry %u...%u\n",
+ bmap_first, bmap_last);
+ /* Write modified sectors from block map. */
+ bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
+ bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
+ n_sectors = bmap_last - bmap_first + 1;
+ offset = s->bmap_sector + bmap_first;
+ base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
+ logout("will write %u block map sectors starting from entry %u\n",
+ n_sectors, bmap_first);
+ ret = bdrv_write(bs->file, offset, base, n_sectors);
}
return ret;
commit a7a43aa199571a336b76a9a9310c95476c6dc5c4
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 19 18:07:49 2012 +0100
vdi: leave bounce buffering to block layer
vdi.c really works as if it implemented bdrv_read and bdrv_write. However,
because only vector I/O is supported by the asynchronous callbacks, it
went through extra pain to bounce-buffer the I/O. This can be handled
by the block layer now that the format is coroutine-based.
Acked-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vdi.c b/block/vdi.c
index 0c1cff6..790b61e 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -144,12 +144,6 @@ void uuid_unparse(const uuid_t uu, char *out)
#endif
typedef struct {
- BlockDriverAIOCB common;
- uint8_t *buf;
- void *orig_buf;
-} VdiAIOCB;
-
-typedef struct {
char text[0x40];
uint32_t signature;
uint32_t version;
@@ -472,31 +466,9 @@ static int coroutine_fn vdi_co_is_allocated(BlockDriverState *bs,
return VDI_IS_ALLOCATED(bmap_entry);
}
-static AIOPool vdi_aio_pool = {
- .aiocb_size = sizeof(VdiAIOCB),
-};
-
-static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov)
+static int vdi_co_read(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors)
{
- VdiAIOCB *acb;
-
- logout("%p, %p\n", bs, qiov);
-
- acb = qemu_aio_get(&vdi_aio_pool, bs, NULL, NULL);
-
- if (qiov->niov > 1) {
- acb->buf = qemu_blockalign(bs, qiov->size);
- acb->orig_buf = acb->buf;
- } else {
- acb->buf = (uint8_t *)qiov->iov->iov_base;
- }
- return acb;
-}
-
-static int vdi_co_readv(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
-{
- VdiAIOCB *acb;
BDRVVdiState *s = bs->opaque;
uint32_t bmap_entry;
uint32_t block_index;
@@ -507,7 +479,6 @@ static int vdi_co_readv(BlockDriverState *bs,
int ret;
logout("\n");
- acb = vdi_aio_setup(bs, qiov);
restart:
block_index = sector_num / s->block_sectors;
@@ -524,13 +495,13 @@ restart:
bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Block not allocated, return zeros, no need to wait. */
- memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
+ memset(buf, 0, n_sectors * SECTOR_SIZE);
ret = 0;
} else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
- hd_iov.iov_base = (void *)acb->buf;
+ hd_iov.iov_base = (void *)buf;
hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
ret = bdrv_co_readv(bs->file, offset, n_sectors, &hd_qiov);
@@ -539,24 +510,18 @@ restart:
nb_sectors -= n_sectors;
sector_num += n_sectors;
- acb->buf += n_sectors * SECTOR_SIZE;
+ buf += n_sectors * SECTOR_SIZE;
if (ret >= 0 && nb_sectors > 0) {
goto restart;
}
- if (acb->orig_buf) {
- qemu_iovec_from_buffer(qiov, acb->orig_buf, qiov->size);
- qemu_vfree(acb->orig_buf);
- }
- qemu_aio_release(acb);
return ret;
}
-static int vdi_co_writev(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+static int vdi_co_write(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors)
{
- VdiAIOCB *acb;
BDRVVdiState *s = bs->opaque;
uint32_t bmap_entry;
uint32_t block_index;
@@ -570,10 +535,6 @@ static int vdi_co_writev(BlockDriverState *bs,
int ret;
logout("\n");
- acb = vdi_aio_setup(bs, qiov);
- if (acb->orig_buf) {
- qemu_iovec_to_buffer(qiov, acb->buf);
- }
restart:
block_index = sector_num / s->block_sectors;
@@ -604,7 +565,7 @@ restart:
/* Copy data to be written to new block and zero unused parts. */
memset(block, 0, sector_in_block * SECTOR_SIZE);
memcpy(block + sector_in_block * SECTOR_SIZE,
- acb->buf, n_sectors * SECTOR_SIZE);
+ buf, n_sectors * SECTOR_SIZE);
memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
(s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
hd_iov.iov_base = (void *)block;
@@ -615,7 +576,7 @@ restart:
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
- hd_iov.iov_base = (void *)acb->buf;
+ hd_iov.iov_base = (void *)buf;
hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
ret = bdrv_co_writev(bs->file, offset, n_sectors, &hd_qiov);
@@ -623,7 +584,7 @@ restart:
nb_sectors -= n_sectors;
sector_num += n_sectors;
- acb->buf += n_sectors * SECTOR_SIZE;
+ buf += n_sectors * SECTOR_SIZE;
logout("%u sectors written\n", n_sectors);
if (ret >= 0 && nb_sectors > 0) {
@@ -666,10 +627,6 @@ restart:
}
}
- if (acb->orig_buf) {
- qemu_vfree(acb->orig_buf);
- }
- qemu_aio_release(acb);
return ret;
}
@@ -821,9 +778,9 @@ static BlockDriver bdrv_vdi = {
.bdrv_co_is_allocated = vdi_co_is_allocated,
.bdrv_make_empty = vdi_make_empty,
- .bdrv_co_readv = vdi_co_readv,
+ .bdrv_read = vdi_co_read,
#if defined(CONFIG_VDI_WRITE)
- .bdrv_co_writev = vdi_co_writev,
+ .bdrv_write = vdi_co_write,
#endif
.bdrv_get_info = vdi_get_info,
commit bfc45fc183619eb4f76e3979598a510f41cd88e3
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 19 18:07:48 2012 +0100
vdi: move aiocb fields to locals
Most of the AIOCB really holds local variables that need to persist
across callback invocation. It can go away now.
Acked-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vdi.c b/block/vdi.c
index 407fccc..0c1cff6 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -145,24 +145,8 @@ void uuid_unparse(const uuid_t uu, char *out)
typedef struct {
BlockDriverAIOCB common;
- int64_t sector_num;
- QEMUIOVector *qiov;
uint8_t *buf;
- /* Total number of sectors. */
- int nb_sectors;
- /* Number of sectors for current AIO. */
- int n_sectors;
- /* New allocated block map entry. */
- uint32_t bmap_first;
- uint32_t bmap_last;
- /* Buffer for new allocated block. */
- void *block_buffer;
void *orig_buf;
- bool is_write;
- int header_modified;
- struct iovec hd_iov;
- QEMUIOVector hd_qiov;
- QEMUBH *bh;
} VdiAIOCB;
typedef struct {
@@ -492,34 +476,20 @@ static AIOPool vdi_aio_pool = {
.aiocb_size = sizeof(VdiAIOCB),
};
-static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, int nb_sectors, int is_write)
+static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov)
{
VdiAIOCB *acb;
- logout("%p, %" PRId64 ", %p, %d, %p, %p, %d\n",
- bs, sector_num, qiov, nb_sectors, is_write);
+ logout("%p, %p\n", bs, qiov);
acb = qemu_aio_get(&vdi_aio_pool, bs, NULL, NULL);
- acb->sector_num = sector_num;
- acb->qiov = qiov;
- acb->is_write = is_write;
if (qiov->niov > 1) {
acb->buf = qemu_blockalign(bs, qiov->size);
acb->orig_buf = acb->buf;
- if (is_write) {
- qemu_iovec_to_buffer(qiov, acb->buf);
- }
} else {
acb->buf = (uint8_t *)qiov->iov->iov_base;
}
- acb->nb_sectors = nb_sectors;
- acb->n_sectors = 0;
- acb->bmap_first = VDI_UNALLOCATED;
- acb->bmap_last = VDI_UNALLOCATED;
- acb->block_buffer = NULL;
- acb->header_modified = 0;
return acb;
}
@@ -532,24 +502,25 @@ static int vdi_co_readv(BlockDriverState *bs,
uint32_t block_index;
uint32_t sector_in_block;
uint32_t n_sectors;
+ struct iovec hd_iov;
+ QEMUIOVector hd_qiov;
int ret;
logout("\n");
- acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, 0);
+ acb = vdi_aio_setup(bs, qiov);
restart:
- block_index = acb->sector_num / s->block_sectors;
- sector_in_block = acb->sector_num % s->block_sectors;
+ block_index = sector_num / s->block_sectors;
+ sector_in_block = sector_num % s->block_sectors;
n_sectors = s->block_sectors - sector_in_block;
- if (n_sectors > acb->nb_sectors) {
- n_sectors = acb->nb_sectors;
+ if (n_sectors > nb_sectors) {
+ n_sectors = nb_sectors;
}
logout("will read %u sectors starting at sector %" PRIu64 "\n",
- n_sectors, acb->sector_num);
+ n_sectors, sector_num);
/* prepare next AIO request */
- acb->n_sectors = n_sectors;
bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Block not allocated, return zeros, no need to wait. */
@@ -559,23 +530,23 @@ restart:
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
- acb->hd_iov.iov_base = (void *)acb->buf;
- acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
- qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- ret = bdrv_co_readv(bs->file, offset, n_sectors, &acb->hd_qiov);
+ hd_iov.iov_base = (void *)acb->buf;
+ hd_iov.iov_len = n_sectors * SECTOR_SIZE;
+ qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
+ ret = bdrv_co_readv(bs->file, offset, n_sectors, &hd_qiov);
}
- logout("%u sectors read\n", acb->n_sectors);
+ logout("%u sectors read\n", n_sectors);
- acb->nb_sectors -= acb->n_sectors;
- acb->sector_num += acb->n_sectors;
- acb->buf += acb->n_sectors * SECTOR_SIZE;
+ nb_sectors -= n_sectors;
+ sector_num += n_sectors;
+ acb->buf += n_sectors * SECTOR_SIZE;
- if (ret >= 0 && acb->nb_sectors > 0) {
+ if (ret >= 0 && nb_sectors > 0) {
goto restart;
}
- if (acb->qiov->niov > 1) {
- qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
+ if (acb->orig_buf) {
+ qemu_iovec_from_buffer(qiov, acb->orig_buf, qiov->size);
qemu_vfree(acb->orig_buf);
}
qemu_aio_release(acb);
@@ -591,96 +562,93 @@ static int vdi_co_writev(BlockDriverState *bs,
uint32_t block_index;
uint32_t sector_in_block;
uint32_t n_sectors;
+ uint32_t bmap_first = VDI_UNALLOCATED;
+ uint32_t bmap_last = VDI_UNALLOCATED;
+ struct iovec hd_iov;
+ QEMUIOVector hd_qiov;
+ uint8_t *block = NULL;
int ret;
logout("\n");
- acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, 1);
+ acb = vdi_aio_setup(bs, qiov);
+ if (acb->orig_buf) {
+ qemu_iovec_to_buffer(qiov, acb->buf);
+ }
restart:
- block_index = acb->sector_num / s->block_sectors;
- sector_in_block = acb->sector_num % s->block_sectors;
+ block_index = sector_num / s->block_sectors;
+ sector_in_block = sector_num % s->block_sectors;
n_sectors = s->block_sectors - sector_in_block;
- if (n_sectors > acb->nb_sectors) {
- n_sectors = acb->nb_sectors;
+ if (n_sectors > nb_sectors) {
+ n_sectors = nb_sectors;
}
logout("will write %u sectors starting at sector %" PRIu64 "\n",
- n_sectors, acb->sector_num);
+ n_sectors, sector_num);
/* prepare next AIO request */
- acb->n_sectors = n_sectors;
bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Allocate new block and write to it. */
uint64_t offset;
- uint8_t *block;
bmap_entry = s->header.blocks_allocated;
s->bmap[block_index] = cpu_to_le32(bmap_entry);
s->header.blocks_allocated++;
offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors;
- block = acb->block_buffer;
if (block == NULL) {
block = g_malloc(s->block_size);
- acb->block_buffer = block;
- acb->bmap_first = block_index;
- assert(!acb->header_modified);
- acb->header_modified = 1;
+ bmap_first = block_index;
}
- acb->bmap_last = block_index;
+ bmap_last = block_index;
/* Copy data to be written to new block and zero unused parts. */
memset(block, 0, sector_in_block * SECTOR_SIZE);
memcpy(block + sector_in_block * SECTOR_SIZE,
acb->buf, n_sectors * SECTOR_SIZE);
memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
(s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
- acb->hd_iov.iov_base = (void *)block;
- acb->hd_iov.iov_len = s->block_size;
- qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- ret = bdrv_co_writev(bs->file, offset, s->block_sectors, &acb->hd_qiov);
+ hd_iov.iov_base = (void *)block;
+ hd_iov.iov_len = s->block_size;
+ qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
+ ret = bdrv_co_writev(bs->file, offset, s->block_sectors, &hd_qiov);
} else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
- acb->hd_iov.iov_base = (void *)acb->buf;
- acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
- qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- ret = bdrv_co_writev(bs->file, offset, n_sectors, &acb->hd_qiov);
+ hd_iov.iov_base = (void *)acb->buf;
+ hd_iov.iov_len = n_sectors * SECTOR_SIZE;
+ qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
+ ret = bdrv_co_writev(bs->file, offset, n_sectors, &hd_qiov);
}
- acb->nb_sectors -= acb->n_sectors;
- acb->sector_num += acb->n_sectors;
- acb->buf += acb->n_sectors * SECTOR_SIZE;
+ nb_sectors -= n_sectors;
+ sector_num += n_sectors;
+ acb->buf += n_sectors * SECTOR_SIZE;
- logout("%u sectors written\n", acb->n_sectors);
- if (ret >= 0 && acb->nb_sectors > 0) {
+ logout("%u sectors written\n", n_sectors);
+ if (ret >= 0 && nb_sectors > 0) {
goto restart;
}
logout("finished data write\n");
if (ret >= 0) {
ret = 0;
- if (acb->header_modified) {
- VdiHeader *header = acb->block_buffer;
+ if (block) {
+ VdiHeader *header = (VdiHeader *) block;
logout("now writing modified header\n");
- assert(VDI_IS_ALLOCATED(acb->bmap_first));
+ assert(VDI_IS_ALLOCATED(bmap_first));
*header = s->header;
vdi_header_to_le(header);
- acb->header_modified = 0;
- acb->hd_iov.iov_base = acb->block_buffer;
- acb->hd_iov.iov_len = SECTOR_SIZE;
- qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- ret = bdrv_co_writev(bs->file, 0, 1, &acb->hd_qiov);
+ hd_iov.iov_base = block;
+ hd_iov.iov_len = SECTOR_SIZE;
+ qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
+ ret = bdrv_co_writev(bs->file, 0, 1, &hd_qiov);
}
- if (ret >= 0 && VDI_IS_ALLOCATED(acb->bmap_first)) {
+ g_free(block);
+ block = NULL;
+ if (ret >= 0 && VDI_IS_ALLOCATED(bmap_first)) {
/* One or more new blocks were allocated. */
uint64_t offset;
- uint32_t bmap_first;
- uint32_t bmap_last;
- g_free(acb->block_buffer);
- acb->block_buffer = NULL;
- bmap_first = acb->bmap_first;
- bmap_last = acb->bmap_last;
logout("now writing modified block map entry %u...%u\n",
bmap_first, bmap_last);
/* Write modified sectors from block map. */
@@ -688,18 +656,17 @@ restart:
bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
n_sectors = bmap_last - bmap_first + 1;
offset = s->bmap_sector + bmap_first;
- acb->bmap_first = VDI_UNALLOCATED;
- acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
+ hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
bmap_first * SECTOR_SIZE);
- acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
- qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+ hd_iov.iov_len = n_sectors * SECTOR_SIZE;
+ qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
logout("will write %u block map sectors starting from entry %u\n",
n_sectors, bmap_first);
- ret = bdrv_co_writev(bs->file, offset, n_sectors, &acb->hd_qiov);
+ ret = bdrv_co_writev(bs->file, offset, n_sectors, &hd_qiov);
}
}
- if (acb->qiov->niov > 1) {
+ if (acb->orig_buf) {
qemu_vfree(acb->orig_buf);
}
qemu_aio_release(acb);
commit 4de659e8eb75df995310c5e57018c5a089c8fc6f
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 19 18:07:47 2012 +0100
vdi: merge aio_read_cb and aio_write_cb into callers
Now inline the former AIO callbacks into vdi_co_readv and vdi_co_writev.
While many cleanups are possible, the code now really looks synchronous.
Acked-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vdi.c b/block/vdi.c
index df0f431..407fccc 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -523,15 +523,19 @@ static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
return acb;
}
-static int vdi_aio_read_cb(void *opaque, int ret)
+static int vdi_co_readv(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{
- VdiAIOCB *acb = opaque;
- BlockDriverState *bs = acb->common.bs;
+ VdiAIOCB *acb;
BDRVVdiState *s = bs->opaque;
uint32_t bmap_entry;
uint32_t block_index;
uint32_t sector_in_block;
uint32_t n_sectors;
+ int ret;
+
+ logout("\n");
+ acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, 0);
restart:
block_index = acb->sector_num / s->block_sectors;
@@ -578,27 +582,19 @@ restart:
return ret;
}
-static int vdi_co_readv(BlockDriverState *bs,
+static int vdi_co_writev(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{
VdiAIOCB *acb;
- int ret;
-
- logout("\n");
- acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, 0);
- ret = vdi_aio_read_cb(acb, 0);
- return ret;
-}
-
-static int vdi_aio_write_cb(void *opaque, int ret)
-{
- VdiAIOCB *acb = opaque;
- BlockDriverState *bs = acb->common.bs;
BDRVVdiState *s = bs->opaque;
uint32_t bmap_entry;
uint32_t block_index;
uint32_t sector_in_block;
uint32_t n_sectors;
+ int ret;
+
+ logout("\n");
+ acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, 1);
restart:
block_index = acb->sector_num / s->block_sectors;
@@ -710,18 +706,6 @@ restart:
return ret;
}
-static int vdi_co_writev(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
-{
- VdiAIOCB *acb;
- int ret;
-
- logout("\n");
- acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, 1);
- ret = vdi_aio_write_cb(acb, 0);
- return ret;
-}
-
static int vdi_create(const char *filename, QEMUOptionParameter *options)
{
int fd;
commit 0c7bfc321b4d19c91a59f1ff7b31418e67b8681a
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 19 18:07:46 2012 +0100
vdi: move end-of-I/O handling at the end
The next step is to take code that only triggers after the first operation,
and move it at the end of vdi_aio_read_cb and vdi_aio_write_cb.
Acked-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vdi.c b/block/vdi.c
index 5fd8700..df0f431 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -533,20 +533,7 @@ static int vdi_aio_read_cb(void *opaque, int ret)
uint32_t sector_in_block;
uint32_t n_sectors;
- logout("%u sectors read\n", acb->n_sectors);
-
restart:
- acb->nb_sectors -= acb->n_sectors;
-
- if (acb->nb_sectors == 0) {
- /* request completed */
- ret = 0;
- goto done;
- }
-
- acb->sector_num += acb->n_sectors;
- acb->buf += acb->n_sectors * SECTOR_SIZE;
-
block_index = acb->sector_num / s->block_sectors;
sector_in_block = acb->sector_num % s->block_sectors;
n_sectors = s->block_sectors - sector_in_block;
@@ -573,11 +560,16 @@ restart:
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
ret = bdrv_co_readv(bs->file, offset, n_sectors, &acb->hd_qiov);
}
- if (ret >= 0) {
+ logout("%u sectors read\n", acb->n_sectors);
+
+ acb->nb_sectors -= acb->n_sectors;
+ acb->sector_num += acb->n_sectors;
+ acb->buf += acb->n_sectors * SECTOR_SIZE;
+
+ if (ret >= 0 && acb->nb_sectors > 0) {
goto restart;
}
-done:
if (acb->qiov->niov > 1) {
qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
qemu_vfree(acb->orig_buf);
@@ -609,56 +601,6 @@ static int vdi_aio_write_cb(void *opaque, int ret)
uint32_t n_sectors;
restart:
- acb->nb_sectors -= acb->n_sectors;
- acb->sector_num += acb->n_sectors;
- acb->buf += acb->n_sectors * SECTOR_SIZE;
-
- if (acb->nb_sectors == 0) {
- logout("finished data write\n");
- acb->n_sectors = 0;
- ret = 0;
- if (acb->header_modified) {
- VdiHeader *header = acb->block_buffer;
- logout("now writing modified header\n");
- assert(VDI_IS_ALLOCATED(acb->bmap_first));
- *header = s->header;
- vdi_header_to_le(header);
- acb->header_modified = 0;
- acb->hd_iov.iov_base = acb->block_buffer;
- acb->hd_iov.iov_len = SECTOR_SIZE;
- qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- ret = bdrv_co_writev(bs->file, 0, 1, &acb->hd_qiov);
- }
- if (ret >= 0 && VDI_IS_ALLOCATED(acb->bmap_first)) {
- /* One or more new blocks were allocated. */
- uint64_t offset;
- uint32_t bmap_first;
- uint32_t bmap_last;
- g_free(acb->block_buffer);
- acb->block_buffer = NULL;
- bmap_first = acb->bmap_first;
- bmap_last = acb->bmap_last;
- logout("now writing modified block map entry %u...%u\n",
- bmap_first, bmap_last);
- /* Write modified sectors from block map. */
- bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
- bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
- n_sectors = bmap_last - bmap_first + 1;
- offset = s->bmap_sector + bmap_first;
- acb->bmap_first = VDI_UNALLOCATED;
- acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
- bmap_first * SECTOR_SIZE);
- acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
- qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- logout("will write %u block map sectors starting from entry %u\n",
- n_sectors, bmap_first);
- ret = bdrv_co_writev(bs->file, offset, n_sectors, &acb->hd_qiov);
- }
- goto done;
- }
-
- logout("%u sectors written\n", acb->n_sectors);
-
block_index = acb->sector_num / s->block_sectors;
sector_in_block = acb->sector_num % s->block_sectors;
n_sectors = s->block_sectors - sector_in_block;
@@ -709,11 +651,58 @@ restart:
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
ret = bdrv_co_writev(bs->file, offset, n_sectors, &acb->hd_qiov);
}
- if (ret >= 0) {
+
+ acb->nb_sectors -= acb->n_sectors;
+ acb->sector_num += acb->n_sectors;
+ acb->buf += acb->n_sectors * SECTOR_SIZE;
+
+ logout("%u sectors written\n", acb->n_sectors);
+ if (ret >= 0 && acb->nb_sectors > 0) {
goto restart;
}
-done:
+ logout("finished data write\n");
+ if (ret >= 0) {
+ ret = 0;
+ if (acb->header_modified) {
+ VdiHeader *header = acb->block_buffer;
+ logout("now writing modified header\n");
+ assert(VDI_IS_ALLOCATED(acb->bmap_first));
+ *header = s->header;
+ vdi_header_to_le(header);
+ acb->header_modified = 0;
+ acb->hd_iov.iov_base = acb->block_buffer;
+ acb->hd_iov.iov_len = SECTOR_SIZE;
+ qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+ ret = bdrv_co_writev(bs->file, 0, 1, &acb->hd_qiov);
+ }
+ if (ret >= 0 && VDI_IS_ALLOCATED(acb->bmap_first)) {
+ /* One or more new blocks were allocated. */
+ uint64_t offset;
+ uint32_t bmap_first;
+ uint32_t bmap_last;
+ g_free(acb->block_buffer);
+ acb->block_buffer = NULL;
+ bmap_first = acb->bmap_first;
+ bmap_last = acb->bmap_last;
+ logout("now writing modified block map entry %u...%u\n",
+ bmap_first, bmap_last);
+ /* Write modified sectors from block map. */
+ bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
+ bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
+ n_sectors = bmap_last - bmap_first + 1;
+ offset = s->bmap_sector + bmap_first;
+ acb->bmap_first = VDI_UNALLOCATED;
+ acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
+ bmap_first * SECTOR_SIZE);
+ acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
+ qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+ logout("will write %u block map sectors starting from entry %u\n",
+ n_sectors, bmap_first);
+ ret = bdrv_co_writev(bs->file, offset, n_sectors, &acb->hd_qiov);
+ }
+ }
+
if (acb->qiov->niov > 1) {
qemu_vfree(acb->orig_buf);
}
commit 3d46a75aa5031788cb283ab4429acca23cf1cf92
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 19 18:07:45 2012 +0100
vdi: basic conversion to coroutines
Even a basic conversion changing the bdrv_aio_readv/bdrv_aio_writev calls
to bdrv_co_readv/bdrv_co_writev, and callbacks to goto statements can
eliminate a lot of code. This is because error handling is simplified
and indirections through bottom halves can go away.
After this patch, I/O to the underlying file already happens via
coroutines, but the code still looks a lot like if asynchronous I/O was
being used.
Acked-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vdi.c b/block/vdi.c
index f8fa865..5fd8700 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -160,7 +160,6 @@ typedef struct {
void *orig_buf;
bool is_write;
int header_modified;
- BlockDriverAIOCB *hd_aiocb;
struct iovec hd_iov;
QEMUIOVector hd_qiov;
QEMUBH *bh;
@@ -489,33 +488,19 @@ static int coroutine_fn vdi_co_is_allocated(BlockDriverState *bs,
return VDI_IS_ALLOCATED(bmap_entry);
}
-static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
-{
- /* TODO: This code is untested. How can I get it executed? */
- VdiAIOCB *acb = container_of(blockacb, VdiAIOCB, common);
- logout("\n");
- if (acb->hd_aiocb) {
- bdrv_aio_cancel(acb->hd_aiocb);
- }
- qemu_aio_release(acb);
-}
-
static AIOPool vdi_aio_pool = {
.aiocb_size = sizeof(VdiAIOCB),
- .cancel = vdi_aio_cancel,
};
static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque, int is_write)
+ QEMUIOVector *qiov, int nb_sectors, int is_write)
{
VdiAIOCB *acb;
logout("%p, %" PRId64 ", %p, %d, %p, %p, %d\n",
- bs, sector_num, qiov, nb_sectors, cb, opaque, is_write);
+ bs, sector_num, qiov, nb_sectors, is_write);
- acb = qemu_aio_get(&vdi_aio_pool, bs, cb, opaque);
- acb->hd_aiocb = NULL;
+ acb = qemu_aio_get(&vdi_aio_pool, bs, NULL, NULL);
acb->sector_num = sector_num;
acb->qiov = qiov;
acb->is_write = is_write;
@@ -538,42 +523,7 @@ static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
return acb;
}
-static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
-{
- logout("\n");
-
- if (acb->bh) {
- return -EIO;
- }
-
- acb->bh = qemu_bh_new(cb, acb);
- if (!acb->bh) {
- return -EIO;
- }
-
- qemu_bh_schedule(acb->bh);
-
- return 0;
-}
-
-static void vdi_aio_read_cb(void *opaque, int ret);
-static void vdi_aio_write_cb(void *opaque, int ret);
-
-static void vdi_aio_rw_bh(void *opaque)
-{
- VdiAIOCB *acb = opaque;
- logout("\n");
- qemu_bh_delete(acb->bh);
- acb->bh = NULL;
-
- if (acb->is_write) {
- vdi_aio_write_cb(opaque, 0);
- } else {
- vdi_aio_read_cb(opaque, 0);
- }
-}
-
-static void vdi_aio_read_cb(void *opaque, int ret)
+static int vdi_aio_read_cb(void *opaque, int ret)
{
VdiAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
@@ -585,12 +535,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
logout("%u sectors read\n", acb->n_sectors);
- acb->hd_aiocb = NULL;
-
- if (ret < 0) {
- goto done;
- }
-
+restart:
acb->nb_sectors -= acb->n_sectors;
if (acb->nb_sectors == 0) {
@@ -618,10 +563,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Block not allocated, return zeros, no need to wait. */
memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
- ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
- if (ret < 0) {
- goto done;
- }
+ ret = 0;
} else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
@@ -629,41 +571,34 @@ static void vdi_aio_read_cb(void *opaque, int ret)
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov,
- n_sectors, vdi_aio_read_cb, acb);
+ ret = bdrv_co_readv(bs->file, offset, n_sectors, &acb->hd_qiov);
+ }
+ if (ret >= 0) {
+ goto restart;
}
- return;
+
done:
if (acb->qiov->niov > 1) {
qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
qemu_vfree(acb->orig_buf);
}
- acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
+ return ret;
}
-static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque)
+static int vdi_co_readv(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{
VdiAIOCB *acb;
int ret;
logout("\n");
- acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
- ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
- if (ret < 0) {
- if (acb->qiov->niov > 1) {
- qemu_vfree(acb->orig_buf);
- }
- qemu_aio_release(acb);
- return NULL;
- }
-
- return &acb->common;
+ acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, 0);
+ ret = vdi_aio_read_cb(acb, 0);
+ return ret;
}
-static void vdi_aio_write_cb(void *opaque, int ret)
+static int vdi_aio_write_cb(void *opaque, int ret)
{
VdiAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
@@ -673,12 +608,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
uint32_t sector_in_block;
uint32_t n_sectors;
- acb->hd_aiocb = NULL;
-
- if (ret < 0) {
- goto done;
- }
-
+restart:
acb->nb_sectors -= acb->n_sectors;
acb->sector_num += acb->n_sectors;
acb->buf += acb->n_sectors * SECTOR_SIZE;
@@ -686,6 +616,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
if (acb->nb_sectors == 0) {
logout("finished data write\n");
acb->n_sectors = 0;
+ ret = 0;
if (acb->header_modified) {
VdiHeader *header = acb->block_buffer;
logout("now writing modified header\n");
@@ -696,10 +627,9 @@ static void vdi_aio_write_cb(void *opaque, int ret)
acb->hd_iov.iov_base = acb->block_buffer;
acb->hd_iov.iov_len = SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1,
- vdi_aio_write_cb, acb);
- return;
- } else if (VDI_IS_ALLOCATED(acb->bmap_first)) {
+ ret = bdrv_co_writev(bs->file, 0, 1, &acb->hd_qiov);
+ }
+ if (ret >= 0 && VDI_IS_ALLOCATED(acb->bmap_first)) {
/* One or more new blocks were allocated. */
uint64_t offset;
uint32_t bmap_first;
@@ -722,11 +652,8 @@ static void vdi_aio_write_cb(void *opaque, int ret)
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
logout("will write %u block map sectors starting from entry %u\n",
n_sectors, bmap_first);
- acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
- n_sectors, vdi_aio_write_cb, acb);
- return;
+ ret = bdrv_co_writev(bs->file, offset, n_sectors, &acb->hd_qiov);
}
- ret = 0;
goto done;
}
@@ -772,9 +699,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
acb->hd_iov.iov_base = (void *)block;
acb->hd_iov.iov_len = s->block_size;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- acb->hd_aiocb = bdrv_aio_writev(bs->file, offset,
- &acb->hd_qiov, s->block_sectors,
- vdi_aio_write_cb, acb);
+ ret = bdrv_co_writev(bs->file, offset, s->block_sectors, &acb->hd_qiov);
} else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
@@ -782,39 +707,30 @@ static void vdi_aio_write_cb(void *opaque, int ret)
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
- n_sectors, vdi_aio_write_cb, acb);
+ ret = bdrv_co_writev(bs->file, offset, n_sectors, &acb->hd_qiov);
+ }
+ if (ret >= 0) {
+ goto restart;
}
-
- return;
done:
if (acb->qiov->niov > 1) {
qemu_vfree(acb->orig_buf);
}
- acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
+ return ret;
}
-static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque)
+static int vdi_co_writev(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{
VdiAIOCB *acb;
int ret;
logout("\n");
- acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
- ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
- if (ret < 0) {
- if (acb->qiov->niov > 1) {
- qemu_vfree(acb->orig_buf);
- }
- qemu_aio_release(acb);
- return NULL;
- }
-
- return &acb->common;
+ acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, 1);
+ ret = vdi_aio_write_cb(acb, 0);
+ return ret;
}
static int vdi_create(const char *filename, QEMUOptionParameter *options)
@@ -965,9 +881,9 @@ static BlockDriver bdrv_vdi = {
.bdrv_co_is_allocated = vdi_co_is_allocated,
.bdrv_make_empty = vdi_make_empty,
- .bdrv_aio_readv = vdi_aio_readv,
+ .bdrv_co_readv = vdi_co_readv,
#if defined(CONFIG_VDI_WRITE)
- .bdrv_aio_writev = vdi_aio_writev,
+ .bdrv_co_writev = vdi_co_writev,
#endif
.bdrv_get_info = vdi_get_info,
commit 1fc86bf963a0617bc9eabfa6c14dbca76cd57976
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Wed Mar 14 15:57:06 2012 +0000
block: enforce constraints on block size properties
Nicolae Mogoreanu <mogo at google.com> noticed that I/O requests can lead
to QEMU crashes when the logical_block_size property is smaller than 512
bytes.
Using the new "blocksize" property we can properly enforce constraints
on the block size such that QEMU's block layer is able to operate
correctly.
Reported-by: Nicolae Mogoreanu <mogo at google.com>
Reported-by: Michael Halcrow <mhalcrow at google.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.h b/block.h
index e670606..c51ab16 100644
--- a/block.h
+++ b/block.h
@@ -435,10 +435,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
DEFINE_PROP_DRIVE("drive", _state, _conf.bs), \
- DEFINE_PROP_UINT16("logical_block_size", _state, \
- _conf.logical_block_size, 512), \
- DEFINE_PROP_UINT16("physical_block_size", _state, \
- _conf.physical_block_size, 512), \
+ DEFINE_PROP_BLOCKSIZE("logical_block_size", _state, \
+ _conf.logical_block_size, 512), \
+ DEFINE_PROP_BLOCKSIZE("physical_block_size", _state, \
+ _conf.physical_block_size, 512), \
DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \
DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \
DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1), \
commit 02fda01c3024463e561820afb0ba09daba4014d9
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Wed Mar 14 15:57:05 2012 +0000
qdev: add blocksize property type
Storage interfaces like virtio-blk can be configured with block size
information so that the guest can take advantage of efficient I/O
request sizes.
According to the SCSI Block Commands (SBC) standard a device's block
size is "almost always greater than one byte and may be a multiple of
512 bytes". QEMU currently has a 512 byte minimum block size because
the block layer functions work at that granularity. Furthermore, the
block size should be a power of 2 because QEMU calculates bitmasks from
the value.
Introduce a "blocksize" property type so devices can enforce these
constraints on block size values. If the constraints are relaxed in the
future then this property can be updated.
Introduce the new PropertyValueNotPowerOf2 QError so QMP clients know
exactly why a block size value was rejected.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index bff9152..98dd06a 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -877,6 +877,52 @@ PropertyInfo qdev_prop_pci_devfn = {
.max = 0xFFFFFFFFULL,
};
+/* --- blocksize --- */
+
+static void set_blocksize(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ int16_t *ptr = qdev_get_prop_ptr(dev, prop);
+ Error *local_err = NULL;
+ int64_t value;
+
+ if (dev->state != DEV_STATE_CREATED) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ return;
+ }
+
+ visit_type_int(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ if (value < prop->info->min || value > prop->info->max) {
+ error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
+ dev->id?:"", name, value, prop->info->min,
+ prop->info->max);
+ return;
+ }
+
+ /* We rely on power-of-2 blocksizes for bitmasks */
+ if ((value & (value - 1)) != 0) {
+ error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
+ dev->id?:"", name, value);
+ return;
+ }
+
+ *ptr = value;
+}
+
+PropertyInfo qdev_prop_blocksize = {
+ .name = "blocksize",
+ .get = get_int16,
+ .set = set_blocksize,
+ .min = 512,
+ .max = 65024,
+};
+
/* --- public helpers --- */
static Property *qdev_prop_walk(Property *props, const char *name)
diff --git a/hw/qdev.h b/hw/qdev.h
index a8df42f..1c10960 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -223,6 +223,7 @@ extern PropertyInfo qdev_prop_drive;
extern PropertyInfo qdev_prop_netdev;
extern PropertyInfo qdev_prop_vlan;
extern PropertyInfo qdev_prop_pci_devfn;
+extern PropertyInfo qdev_prop_blocksize;
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
.name = (_name), \
@@ -284,6 +285,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
LostTickPolicy)
+#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
+ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
#define DEFINE_PROP_END_OF_LIST() \
{}
diff --git a/qerror.c b/qerror.c
index 1f565fc..96fbe71 100644
--- a/qerror.c
+++ b/qerror.c
@@ -241,6 +241,11 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Property '%(device).%(property)' can't find value '%(value)'",
},
{
+ .error_fmt = QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
+ .desc = "Property '%(device).%(property)' doesn't take "
+ "value '%(value)', it's not a power of 2",
+ },
+ {
.error_fmt = QERR_PROPERTY_VALUE_OUT_OF_RANGE,
.desc = "Property '%(device).%(property)' doesn't take "
"value %(value) (minimum: %(min), maximum: %(max))",
diff --git a/qerror.h b/qerror.h
index e16f9c2..5c23c1f 100644
--- a/qerror.h
+++ b/qerror.h
@@ -202,6 +202,10 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_PROPERTY_VALUE_NOT_FOUND \
"{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+#define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \
+ "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
+ "'device': %s, 'property': %s, 'value': %"PRId64" } }"
+
#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
"{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
commit 41453412ca16ff1871ed2bd6ee83cb9a5c734823
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Wed Mar 14 15:57:04 2012 +0000
qerror: fix QERR_PROPERTY_VALUE_OUT_OF_RANGE description
Fix a typo in the description for QERR_PROPERTY_VALUE_OUT_OF_RANGE where
"'" was used instead of ")".
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/qerror.c b/qerror.c
index 41c729a..1f565fc 100644
--- a/qerror.c
+++ b/qerror.c
@@ -243,7 +243,7 @@ static const QErrorStringTable qerror_table[] = {
{
.error_fmt = QERR_PROPERTY_VALUE_OUT_OF_RANGE,
.desc = "Property '%(device).%(property)' doesn't take "
- "value %(value) (minimum: %(min), maximum: %(max)'",
+ "value %(value) (minimum: %(min), maximum: %(max))",
},
{
.error_fmt = QERR_QGA_COMMAND_FAILED,
commit c088b691363070d151f80cc1fde4b7c151bdfe8f
Author: Zhang Shengju <zhangsju at gmail.com>
Date: Tue Mar 13 22:38:13 2012 +0800
block/vpc: write checksum back to footer after check
After validation check, the 'checksum' is not written back
to footer, which leave it with zero.
This results in errors while loadding it under Microsoft's
Hyper-V environment, and also errors from utilities like
Citrix's vhd-util.
Signed-off-by: Zhang Shengju <sean_zhang at trendmicro.com.cn>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vpc.c b/block/vpc.c
index 706faf3..5cd13d1 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -189,6 +189,9 @@ static int vpc_open(BlockDriverState *bs, int flags)
fprintf(stderr, "block-vpc: The header checksum of '%s' is "
"incorrect.\n", bs->filename);
+ /* Write 'checksum' back to footer, or else will leave it with zero. */
+ footer->checksum = be32_to_cpu(checksum);
+
// The visible size of a image in Virtual PC depends on the geometry
// rather than on the size stored in the footer (the size in the footer
// is too large usually)
commit 95ebda85e09ed2b7f00deb2adbdafa5ccf5db948
Author: Floris Bos <bos at je-eigen-domein.nl>
Date: Tue Mar 13 13:31:47 2012 +0100
ide: Adds wwn=hex qdev option
Allow the user to specify a disk's World Wide Name.
Linux guests can address disks by their unique World Wide Name number
(e.g. /dev/disk/by-id/wwn-0x5001517959123522). This patch adds support
for assigning a World Wide Name number to a virtual IDE disk.
Cc: kwolf at redhat.com
Signed-off-by: Floris Bos <dev at noc-ps.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 5647694..6e25338 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -142,8 +142,12 @@ static void ide_identify(IDEState *s)
put_le16(p + 82, (1 << 14) | (1 << 5) | 1);
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
- /* 14=set to 1, 1=SMART self test, 0=SMART error logging */
- put_le16(p + 84, (1 << 14) | 0);
+ /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
+ if (s->wwn) {
+ put_le16(p + 84, (1 << 14) | (1 << 8) | 0);
+ } else {
+ put_le16(p + 84, (1 << 14) | 0);
+ }
/* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
if (bdrv_enable_write_cache(s->bs))
put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
@@ -151,8 +155,12 @@ static void ide_identify(IDEState *s)
put_le16(p + 85, (1 << 14) | 1);
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
put_le16(p + 86, (1 << 13) | (1 <<12) | (1 << 10));
- /* 14=set to 1, 1=smart self test, 0=smart error logging */
- put_le16(p + 87, (1 << 14) | 0);
+ /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
+ if (s->wwn) {
+ put_le16(p + 87, (1 << 14) | (1 << 8) | 0);
+ } else {
+ put_le16(p + 87, (1 << 14) | 0);
+ }
put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
put_le16(p + 93, 1 | (1 << 14) | 0x2000);
put_le16(p + 100, s->nb_sectors);
@@ -162,6 +170,13 @@ static void ide_identify(IDEState *s)
if (dev && dev->conf.physical_block_size)
put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
+ if (s->wwn) {
+ /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
+ put_le16(p + 108, s->wwn >> 48);
+ put_le16(p + 109, s->wwn >> 32);
+ put_le16(p + 110, s->wwn >> 16);
+ put_le16(p + 111, s->wwn);
+ }
if (dev && dev->conf.discard_granularity) {
put_le16(p + 169, 1); /* TRIM support */
}
@@ -1833,7 +1848,8 @@ static const BlockDevOps ide_cd_block_ops = {
};
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
- const char *version, const char *serial, const char *model)
+ const char *version, const char *serial, const char *model,
+ uint64_t wwn)
{
int cylinders, heads, secs;
uint64_t nb_sectors;
@@ -1859,6 +1875,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
s->heads = heads;
s->sectors = secs;
s->nb_sectors = nb_sectors;
+ s->wwn = wwn;
/* The SMART values should be preserved across power cycles
but they aren't. */
s->smart_enabled = 1;
@@ -1993,7 +2010,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
if (ide_init_drive(&bus->ifs[i], dinfo->bdrv,
dinfo->media_cd ? IDE_CD : IDE_HD, NULL,
*dinfo->serial ? dinfo->serial : NULL,
- NULL) < 0) {
+ NULL, 0) < 0) {
error_report("Can't set up IDE drive %s", dinfo->id);
exit(1);
}
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index b1319dc..100efd3 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -349,6 +349,7 @@ struct IDEState {
int drive_serial;
char drive_serial_str[21];
char drive_model_str[41];
+ uint64_t wwn;
/* ide regs */
uint8_t feature;
uint8_t error;
@@ -470,6 +471,7 @@ struct IDEDevice {
char *version;
char *serial;
char *model;
+ uint64_t wwn;
};
#define BM_STATUS_DMAING 0x01
@@ -536,7 +538,8 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
uint32_t ide_data_readl(void *opaque, uint32_t addr);
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
- const char *version, const char *serial, const char *model);
+ const char *version, const char *serial, const char *model,
+ uint64_t wwn);
void ide_init2(IDEBus *bus, qemu_irq irq);
void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
DriveInfo *hd1, qemu_irq irq);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 07227c7..a46578d 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -137,7 +137,7 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
}
if (ide_init_drive(s, dev->conf.bs, kind,
- dev->version, serial, dev->model) < 0) {
+ dev->version, serial, dev->model, dev->wwn) < 0) {
return -1;
}
@@ -174,6 +174,7 @@ static int ide_drive_initfn(IDEDevice *dev)
#define DEFINE_IDE_DEV_PROPERTIES() \
DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \
DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \
+ DEFINE_PROP_HEX64("wwn", IDEDrive, dev.wwn, 0), \
DEFINE_PROP_STRING("serial", IDEDrive, dev.serial),\
DEFINE_PROP_STRING("model", IDEDrive, dev.model)
commit aa2c91bdfebbfa314e9522573a9656626e21ac67
Author: Floris Bos <bos at je-eigen-domein.nl>
Date: Mon Mar 12 21:05:10 2012 +0100
ide: Change serial number strncpy() to pstrcpy()
strncpy may not null-terminate the destination string.
Cc: kwolf at redhat.com
Signed-off-by: Floris Bos <dev at noc-ps.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/blockdev.c b/blockdev.c
index 1a500b8..f5e7dba 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -532,8 +532,9 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
dinfo->unit = unit_id;
dinfo->opts = opts;
dinfo->refcount = 1;
- if (serial)
- strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
+ if (serial) {
+ pstrcpy(dinfo->serial, sizeof(dinfo->serial), serial);
+ }
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index e38cace..5647694 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1879,7 +1879,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
}
}
if (serial) {
- strncpy(s->drive_serial_str, serial, sizeof(s->drive_serial_str));
+ pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), serial);
} else {
snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
"QM%05d", s->drive_serial);
commit 27e0c9a1bbd166a67c16291016fba298a8e47140
Author: Floris Bos <bos at je-eigen-domein.nl>
Date: Mon Mar 12 21:05:09 2012 +0100
ide: Add "model=s" qdev option
Allow the user to override the default disk model name "QEMU HARDDISK".
Some Linux distributions use the /dev/disk/by-id/scsi-SATA_name-of-disk-
model_serial addressing scheme when refering to partitions in /etc/fstab
and elsewhere. This causes problems when starting a disk image taken from
an existing physical server under qemu, because when running under qemu
name-of-disk-model is always "QEMU HARDDISK".
This patch introduces a model=s option which in combination with the
existing serial=s option can be used to fake the disk the operating
system was previously on, allowing the OS to boot properly.
Cc: kwolf at redhat.com
Signed-off-by: Floris Bos <dev at noc-ps.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 771811c..e38cace 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -100,7 +100,7 @@ static void ide_identify(IDEState *s)
put_le16(p + 21, 512); /* cache size in sectors */
put_le16(p + 22, 4); /* ecc bytes */
padstr((char *)(p + 23), s->version, 8); /* firmware version */
- padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
+ padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
#if MAX_MULT_SECTORS > 1
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
#endif
@@ -188,7 +188,7 @@ static void ide_atapi_identify(IDEState *s)
put_le16(p + 21, 512); /* cache size in sectors */
put_le16(p + 22, 4); /* ecc bytes */
padstr((char *)(p + 23), s->version, 8); /* firmware version */
- padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */
+ padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
#ifdef USE_DMA_CDROM
put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
@@ -245,7 +245,7 @@ static void ide_cfata_identify(IDEState *s)
padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
put_le16(p + 22, 0x0004); /* ECC bytes */
padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */
- padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
+ padstr((char *) (p + 27), s->drive_model_str, 40);/* Model number */
#if MAX_MULT_SECTORS > 1
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
#else
@@ -1833,7 +1833,7 @@ static const BlockDevOps ide_cd_block_ops = {
};
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
- const char *version, const char *serial)
+ const char *version, const char *serial, const char *model)
{
int cylinders, heads, secs;
uint64_t nb_sectors;
@@ -1884,6 +1884,22 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
"QM%05d", s->drive_serial);
}
+ if (model) {
+ pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), model);
+ } else {
+ switch (kind) {
+ case IDE_CD:
+ strcpy(s->drive_model_str, "QEMU DVD-ROM");
+ break;
+ case IDE_CFATA:
+ strcpy(s->drive_model_str, "QEMU MICRODRIVE");
+ break;
+ default:
+ strcpy(s->drive_model_str, "QEMU HARDDISK");
+ break;
+ }
+ }
+
if (version) {
pstrcpy(s->version, sizeof(s->version), version);
} else {
@@ -1976,7 +1992,8 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
if (dinfo) {
if (ide_init_drive(&bus->ifs[i], dinfo->bdrv,
dinfo->media_cd ? IDE_CD : IDE_HD, NULL,
- *dinfo->serial ? dinfo->serial : NULL) < 0) {
+ *dinfo->serial ? dinfo->serial : NULL,
+ NULL) < 0) {
error_report("Can't set up IDE drive %s", dinfo->id);
exit(1);
}
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index c808a0d..b1319dc 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -348,6 +348,7 @@ struct IDEState {
uint8_t identify_data[512];
int drive_serial;
char drive_serial_str[21];
+ char drive_model_str[41];
/* ide regs */
uint8_t feature;
uint8_t error;
@@ -468,6 +469,7 @@ struct IDEDevice {
BlockConf conf;
char *version;
char *serial;
+ char *model;
};
#define BM_STATUS_DMAING 0x01
@@ -534,7 +536,7 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
uint32_t ide_data_readl(void *opaque, uint32_t addr);
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
- const char *version, const char *serial);
+ const char *version, const char *serial, const char *model);
void ide_init2(IDEBus *bus, qemu_irq irq);
void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
DriveInfo *hd1, qemu_irq irq);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index f6a4896..07227c7 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -136,7 +136,8 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
}
}
- if (ide_init_drive(s, dev->conf.bs, kind, dev->version, serial) < 0) {
+ if (ide_init_drive(s, dev->conf.bs, kind,
+ dev->version, serial, dev->model) < 0) {
return -1;
}
@@ -173,7 +174,8 @@ static int ide_drive_initfn(IDEDevice *dev)
#define DEFINE_IDE_DEV_PROPERTIES() \
DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \
DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \
- DEFINE_PROP_STRING("serial", IDEDrive, dev.serial)
+ DEFINE_PROP_STRING("serial", IDEDrive, dev.serial),\
+ DEFINE_PROP_STRING("model", IDEDrive, dev.model)
static Property ide_hd_properties[] = {
DEFINE_IDE_DEV_PROPERTIES(),
commit 2844bdd99a96dc32a6ebf464f49e65be31da1c14
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Mar 13 14:44:22 2012 +0100
ide: IDENTIFY word 86 bit 14 is reserved
Reserved bits should be cleared to zero.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 6f06d28..771811c 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -150,7 +150,7 @@ static void ide_identify(IDEState *s)
else
put_le16(p + 85, (1 << 14) | 1);
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
- put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
+ put_le16(p + 86, (1 << 13) | (1 <<12) | (1 << 10));
/* 14=set to 1, 1=smart self test, 0=smart error logging */
put_le16(p + 87, (1 << 14) | 0);
put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
commit 85e8dab1efc7228bb674e72f6fb3be78c1e883bf
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 12 17:01:48 2012 +0100
aio: move BlockDriverAIOCB to qemu-aio.h
And remove several block_int.h inclusions that should not be there.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.h b/block.h
index 415bb17..e670606 100644
--- a/block.h
+++ b/block.h
@@ -180,8 +180,6 @@ typedef struct BdrvCheckResult {
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res);
/* async block I/O */
-typedef struct BlockDriverAIOCB BlockDriverAIOCB;
-typedef void BlockDriverCompletionFunc(void *opaque, int ret);
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
int sector_num);
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
diff --git a/block_int.h b/block_int.h
index b460c36..22c86a5 100644
--- a/block_int.h
+++ b/block_int.h
@@ -53,12 +53,6 @@
typedef struct BdrvTrackedRequest BdrvTrackedRequest;
-typedef struct AIOPool {
- void (*cancel)(BlockDriverAIOCB *acb);
- int aiocb_size;
- BlockDriverAIOCB *free_aiocb;
-} AIOPool;
-
typedef struct BlockIOLimit {
int64_t bps[3];
int64_t iops[3];
@@ -302,20 +296,8 @@ struct BlockDriverState {
BlockJob *job;
};
-struct BlockDriverAIOCB {
- AIOPool *pool;
- BlockDriverState *bs;
- BlockDriverCompletionFunc *cb;
- void *opaque;
- BlockDriverAIOCB *next;
-};
-
void get_tmp_filename(char *filename, int size);
-void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque);
-void qemu_aio_release(void *p);
-
void bdrv_set_io_limits(BlockDriverState *bs,
BlockIOLimit *io_limits);
diff --git a/dma-helpers.c b/dma-helpers.c
index c29ea6d..7fcc86d 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -8,7 +8,6 @@
*/
#include "dma.h"
-#include "block_int.h"
#include "trace.h"
void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 4d568ac..6f06d28 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -31,7 +31,6 @@
#include "sysemu.h"
#include "dma.h"
#include "blockdev.h"
-#include "block_int.h"
#include <hw/ide/internal.h>
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index edc09b7..f022a02 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -15,7 +15,6 @@
#include "hw.h"
#include "pci.h"
#include "scsi.h"
-#include "block_int.h"
#include "dma.h"
//#define DEBUG_LSI
diff --git a/linux-aio.c b/linux-aio.c
index d2fc2e7..15261ec 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -9,7 +9,6 @@
*/
#include "qemu-common.h"
#include "qemu-aio.h"
-#include "block_int.h"
#include "block/raw-posix-aio.h"
#include <sys/eventfd.h>
diff --git a/qemu-aio.h b/qemu-aio.h
index 3bdd749..230c2f7 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -17,6 +17,27 @@
#include "qemu-common.h"
#include "qemu-char.h"
+typedef struct BlockDriverAIOCB BlockDriverAIOCB;
+typedef void BlockDriverCompletionFunc(void *opaque, int ret);
+
+typedef struct AIOPool {
+ void (*cancel)(BlockDriverAIOCB *acb);
+ int aiocb_size;
+ BlockDriverAIOCB *free_aiocb;
+} AIOPool;
+
+struct BlockDriverAIOCB {
+ AIOPool *pool;
+ BlockDriverState *bs;
+ BlockDriverCompletionFunc *cb;
+ void *opaque;
+ BlockDriverAIOCB *next;
+};
+
+void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
+void qemu_aio_release(void *p);
+
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
typedef int (AioFlushHandler)(void *opaque);
commit 29cdb2513c3f22f51d6f3585b41009576485cb35
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 12 18:26:01 2012 +0100
block: push recursive flushing up from drivers
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index b88ee90..8858be0 100644
--- a/block.c
+++ b/block.c
@@ -2331,9 +2331,7 @@ void bdrv_flush_all(void)
BlockDriverState *bs;
QTAILQ_FOREACH(bs, &bdrv_states, list) {
- if (!bdrv_is_read_only(bs) && bdrv_is_inserted(bs)) {
- bdrv_flush(bs);
- }
+ bdrv_flush(bs);
}
}
@@ -3520,7 +3518,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
{
int ret;
- if (!bs->drv) {
+ if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
return 0;
}
@@ -3538,7 +3536,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
}
if (bs->drv->bdrv_co_flush_to_disk) {
- return bs->drv->bdrv_co_flush_to_disk(bs);
+ ret = bs->drv->bdrv_co_flush_to_disk(bs);
} else if (bs->drv->bdrv_aio_flush) {
BlockDriverAIOCB *acb;
CoroutineIOCompletion co = {
@@ -3547,10 +3545,10 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
acb = bs->drv->bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
if (acb == NULL) {
- return -EIO;
+ ret = -EIO;
} else {
qemu_coroutine_yield();
- return co.ret;
+ ret = co.ret;
}
} else {
/*
@@ -3564,8 +3562,16 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
*
* Let's hope the user knows what he's doing.
*/
- return 0;
+ ret = 0;
}
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Now flush the underlying protocol. It will also have BDRV_O_NO_FLUSH
+ * in the case of cache=unsafe, so there are no useless flushes.
+ */
+ return bdrv_co_flush(bs->file);
}
void bdrv_invalidate_cache(BlockDriverState *bs)
diff --git a/block/blkdebug.c b/block/blkdebug.c
index a251802..e56e37d 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -397,12 +397,6 @@ static void blkdebug_close(BlockDriverState *bs)
}
}
-static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque)
-{
- return bdrv_aio_flush(bs->file, cb, opaque);
-}
-
static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
BlkdebugVars *old_vars)
{
@@ -452,7 +446,6 @@ static BlockDriver bdrv_blkdebug = {
.bdrv_aio_readv = blkdebug_aio_readv,
.bdrv_aio_writev = blkdebug_aio_writev,
- .bdrv_aio_flush = blkdebug_aio_flush,
.bdrv_debug_event = blkdebug_debug_event,
};
diff --git a/block/cow.c b/block/cow.c
index bb5927c..8d3c9f8 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -318,11 +318,6 @@ exit:
return ret;
}
-static coroutine_fn int cow_co_flush(BlockDriverState *bs)
-{
- return bdrv_co_flush(bs->file);
-}
-
static QEMUOptionParameter cow_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
@@ -348,7 +343,6 @@ static BlockDriver bdrv_cow = {
.bdrv_read = cow_co_read,
.bdrv_write = cow_co_write,
- .bdrv_co_flush_to_disk = cow_co_flush,
.bdrv_co_is_allocated = cow_co_is_allocated,
.create_options = cow_create_options,
diff --git a/block/qcow.c b/block/qcow.c
index b1cfe1f..35dff49 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -835,11 +835,6 @@ fail:
return ret;
}
-static coroutine_fn int qcow_co_flush(BlockDriverState *bs)
-{
- return bdrv_co_flush(bs->file);
-}
-
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVQcowState *s = bs->opaque;
@@ -877,7 +872,6 @@ static BlockDriver bdrv_qcow = {
.bdrv_co_readv = qcow_co_readv,
.bdrv_co_writev = qcow_co_writev,
- .bdrv_co_flush_to_disk = qcow_co_flush,
.bdrv_co_is_allocated = qcow_co_is_allocated,
.bdrv_set_key = qcow_set_key,
diff --git a/block/qcow2.c b/block/qcow2.c
index 7aece65..70d3141 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1253,11 +1253,6 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
return 0;
}
-static coroutine_fn int qcow2_co_flush_to_disk(BlockDriverState *bs)
-{
- return bdrv_co_flush(bs->file);
-}
-
static int64_t qcow2_vm_state_offset(BDRVQcowState *s)
{
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
@@ -1377,7 +1372,6 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_co_readv = qcow2_co_readv,
.bdrv_co_writev = qcow2_co_writev,
.bdrv_co_flush_to_os = qcow2_co_flush_to_os,
- .bdrv_co_flush_to_disk = qcow2_co_flush_to_disk,
.bdrv_co_discard = qcow2_co_discard,
.bdrv_truncate = qcow2_truncate,
diff --git a/block/qed.c b/block/qed.c
index a041d31..d6c1580 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1350,13 +1350,6 @@ static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
opaque, QED_AIOCB_WRITE);
}
-static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
- BlockDriverCompletionFunc *cb,
- void *opaque)
-{
- return bdrv_aio_flush(bs->file, cb, opaque);
-}
-
typedef struct {
Coroutine *co;
int ret;
@@ -1562,7 +1555,6 @@ static BlockDriver bdrv_qed = {
.bdrv_make_empty = bdrv_qed_make_empty,
.bdrv_aio_readv = bdrv_qed_aio_readv,
.bdrv_aio_writev = bdrv_qed_aio_writev,
- .bdrv_aio_flush = bdrv_qed_aio_flush,
.bdrv_co_write_zeroes = bdrv_qed_co_write_zeroes,
.bdrv_truncate = bdrv_qed_truncate,
.bdrv_getlength = bdrv_qed_getlength,
diff --git a/block/raw.c b/block/raw.c
index 1cdac0c..7086e31 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -25,11 +25,6 @@ static void raw_close(BlockDriverState *bs)
{
}
-static int coroutine_fn raw_co_flush(BlockDriverState *bs)
-{
- return bdrv_co_flush(bs->file);
-}
-
static int64_t raw_getlength(BlockDriverState *bs)
{
return bdrv_getlength(bs->file);
@@ -113,7 +108,6 @@ static BlockDriver bdrv_raw = {
.bdrv_co_readv = raw_co_readv,
.bdrv_co_writev = raw_co_writev,
- .bdrv_co_flush_to_disk = raw_co_flush,
.bdrv_co_discard = raw_co_discard,
.bdrv_probe = raw_probe,
diff --git a/block/vdi.c b/block/vdi.c
index 6a0011f..f8fa865 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -930,13 +930,6 @@ static void vdi_close(BlockDriverState *bs)
error_free(s->migration_blocker);
}
-static coroutine_fn int vdi_co_flush(BlockDriverState *bs)
-{
- logout("\n");
- return bdrv_co_flush(bs->file);
-}
-
-
static QEMUOptionParameter vdi_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
@@ -969,7 +962,6 @@ static BlockDriver bdrv_vdi = {
.bdrv_open = vdi_open,
.bdrv_close = vdi_close,
.bdrv_create = vdi_create,
- .bdrv_co_flush_to_disk = vdi_co_flush,
.bdrv_co_is_allocated = vdi_co_is_allocated,
.bdrv_make_empty = vdi_make_empty,
diff --git a/block/vmdk.c b/block/vmdk.c
index 45c003a..18e9b4c 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1525,10 +1525,10 @@ static void vmdk_close(BlockDriverState *bs)
static coroutine_fn int vmdk_co_flush(BlockDriverState *bs)
{
- int i, ret, err;
BDRVVmdkState *s = bs->opaque;
+ int i, err;
+ int ret = 0;
- ret = bdrv_co_flush(bs->file);
for (i = 0; i < s->num_extents; i++) {
err = bdrv_co_flush(s->extents[i].file);
if (err < 0) {
diff --git a/block/vpc.c b/block/vpc.c
index 6b4816f..706faf3 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -507,11 +507,6 @@ static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
return ret;
}
-static coroutine_fn int vpc_co_flush(BlockDriverState *bs)
-{
- return bdrv_co_flush(bs->file);
-}
-
/*
* Calculates the number of cylinders, heads and sectors per cylinder
* based on a given number of sectors. This is the algorithm described
@@ -789,7 +784,6 @@ static BlockDriver bdrv_vpc = {
.bdrv_read = vpc_co_read,
.bdrv_write = vpc_co_write,
- .bdrv_co_flush_to_disk = vpc_co_flush,
.create_options = vpc_create_options,
};
commit d7bb72c83cfbcfd0563e158800e4052819223524
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Mon Mar 12 16:36:07 2012 +0000
qemu-io: add option to enable tracing
It can be useful to enable QEMU tracing when trying out block layer
interfaces via qemu-io. Tracing can be enabled using the new -T FILE
option where the given file contains a list of trace events to enable
(just like the qemu --trace events=FILE option).
$ echo qemu_vfree >my-events
$ ./qemu-io -T my-events ...
Remember to use ./configure --enable-trace-backend=BACKEND when building
qemu-io.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/qemu-io.c b/qemu-io.c
index 3189530..e6fcd77 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -17,6 +17,7 @@
#include "qemu-common.h"
#include "block_int.h"
#include "cmd.h"
+#include "trace/control.h"
#define VERSION "0.0.1"
@@ -1783,6 +1784,7 @@ static void usage(const char *name)
" -g, --growable allow file to grow (only applies to protocols)\n"
" -m, --misalign misalign allocations for O_DIRECT\n"
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
+" -T, --trace FILE enable trace events listed in the given file\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
"\n",
@@ -1794,7 +1796,7 @@ int main(int argc, char **argv)
{
int readonly = 0;
int growable = 0;
- const char *sopt = "hVc:rsnmgk";
+ const char *sopt = "hVc:rsnmgkT:";
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
@@ -1806,6 +1808,7 @@ int main(int argc, char **argv)
{ "misalign", 0, NULL, 'm' },
{ "growable", 0, NULL, 'g' },
{ "native-aio", 0, NULL, 'k' },
+ { "trace", 1, NULL, 'T' },
{ NULL, 0, NULL, 0 }
};
int c;
@@ -1837,6 +1840,11 @@ int main(int argc, char **argv)
case 'k':
flags |= BDRV_O_NATIVE_AIO;
break;
+ case 'T':
+ if (!trace_backend_init(optarg, NULL)) {
+ exit(1); /* error message will have been printed */
+ }
+ break;
case 'V':
printf("%s version %s\n", progname, VERSION);
exit(0);
commit 3948d1d4876065160583e79533bf604481063833
Author: Kevin Wolf <kwolf at redhat.com>
Date: Mon Mar 12 17:46:51 2012 +0100
qcow2: Remove unused parameter in get_cluster_table()
Since everything goes through the cache, callers don't use the L2 table
offset any more.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index e0fb907..cbd224d 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -466,7 +466,6 @@ out:
*/
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
uint64_t **new_l2_table,
- uint64_t *new_l2_offset,
int *new_l2_index)
{
BDRVQcowState *s = bs->opaque;
@@ -514,7 +513,6 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
*new_l2_table = l2_table;
- *new_l2_offset = l2_offset;
*new_l2_index = l2_index;
return 0;
@@ -539,11 +537,11 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
{
BDRVQcowState *s = bs->opaque;
int l2_index, ret;
- uint64_t l2_offset, *l2_table;
+ uint64_t *l2_table;
int64_t cluster_offset;
int nb_csectors;
- ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+ ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
if (ret < 0) {
return 0;
}
@@ -588,7 +586,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
{
BDRVQcowState *s = bs->opaque;
int i, j = 0, l2_index, ret;
- uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
+ uint64_t *old_cluster, start_sect, *l2_table;
uint64_t cluster_offset = m->alloc_offset;
bool cow = false;
@@ -633,7 +631,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
}
qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
- ret = get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index);
+ ret = get_cluster_table(bs, m->offset, &l2_table, &l2_index);
if (ret < 0) {
goto err;
}
@@ -817,7 +815,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
{
BDRVQcowState *s = bs->opaque;
int l2_index, ret, sectors;
- uint64_t l2_offset, *l2_table;
+ uint64_t *l2_table;
unsigned int nb_clusters, keep_clusters;
uint64_t cluster_offset;
@@ -825,7 +823,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
n_start, n_end);
/* Find L2 entry for the first involved cluster */
- ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+ ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
if (ret < 0) {
return ret;
}
@@ -1000,12 +998,12 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
unsigned int nb_clusters)
{
BDRVQcowState *s = bs->opaque;
- uint64_t l2_offset, *l2_table;
+ uint64_t *l2_table;
int l2_index;
int ret;
int i;
- ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+ ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
if (ret < 0) {
return ret;
}
commit fa6b8733c93107d7fcd7018d1822e93ba9edaa94
Author: Kevin Wolf <kwolf at redhat.com>
Date: Mon Mar 12 10:30:02 2012 +0100
tracetool: Forbid argument name 'next'
It has happened more than once that patches that look perfectly sane
and work with simpletrace broke systemtap because they use 'next' as an
argument name for a tracing function. However, 'next' is a keyword for
systemtap, so we shouldn't use it.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/scripts/tracetool b/scripts/tracetool
index 47389b6..7b1c142 100755
--- a/scripts/tracetool
+++ b/scripts/tracetool
@@ -81,6 +81,10 @@ get_args()
args=${1#*\(}
args=${args%%\)*}
echo "$args"
+
+ if (echo "$args" | grep "[ *]next\($\|[, ]\)" > /dev/null 2>&1); then
+ echo -e "\n#error 'next' is a bad argument name (clash with systemtap keyword)\n "
+ fi
}
# Get the argument name list of a trace event
commit bfe24e1a26d33d57df3c75e7f44273f0b0ca5943
Author: Kevin Wolf <kwolf at redhat.com>
Date: Mon Mar 12 10:28:34 2012 +0100
trace-events: Rename 'next' argument
'next' is a systemtap keyword, so it's a bad idea to use it as an
argument name.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/trace-events b/trace-events
index db2cd39..a5f276d 100644
--- a/trace-events
+++ b/trace-events
@@ -562,7 +562,7 @@ qemu_coroutine_terminate(void *co) "self %p"
# qemu-coroutine-lock.c
qemu_co_queue_next_bh(void) ""
-qemu_co_queue_next(void *next) "next %p"
+qemu_co_queue_next(void *nxt) "next %p"
qemu_co_mutex_lock_entry(void *mutex, void *self) "mutex %p self %p"
qemu_co_mutex_lock_return(void *mutex, void *self) "mutex %p self %p"
qemu_co_mutex_unlock_entry(void *mutex, void *self) "mutex %p self %p"
commit 221b3a3f1e5edb9e41a48bfa384803800184b397
Author: Julien Grall <julien.grall at citrix.com>
Date: Wed Apr 4 15:15:41 2012 +0100
memory: check address space when a listener is registered
This patch resolves a bug in memory listener registration.
"range_add" callback was called on each section of the both
address space (IO and memory space) even if it doesn't match
the address space filter.
Signed-off-by: Julien Grall <julien.grall at citrix.com>
Signed-off-by: Avi Kivity <avi at redhat.com>
diff --git a/memory.c b/memory.c
index a3f5b59..aab4a31 100644
--- a/memory.c
+++ b/memory.c
@@ -1444,6 +1444,11 @@ static void listener_add_address_space(MemoryListener *listener,
{
FlatRange *fr;
+ if (listener->address_space_filter
+ && listener->address_space_filter != as->root) {
+ return;
+ }
+
if (global_dirty_log) {
listener->log_global_start(listener);
}
commit 8f8d364f2447e58768132fc10f48a67af371ee38
Merge: a7be9ba... b8ba679...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Wed Apr 4 20:45:03 2012 +0000
Merge branch 's390-for-upstream' of git://repo.or.cz/qemu/agraf
* 's390-for-upstream' of git://repo.or.cz/qemu/agraf:
target-s390x: Update s390x_{tod,cpu}_timer() to use S390CPU
target-s390x: QOM'ify CPU init
target-s390x: QOM'ify CPU reset
target-s390x: QOM'ify CPU
commit a7be9bad33d81d4bab2a51935b5443d258e7d082
Author: Artyom Tarasenko <atar4qemu at gmail.com>
Date: Tue Apr 3 17:49:05 2012 +0200
Improve interrupt handling priority
The vector interrupt has higher priority than interrupt_level_n.
Also check only interrupt_level_n concurency when TL > 0, the traps of
other types may be nested.
Signed-off-by: Artyom Tarasenko <atar4qemu at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 50bc0d2..fe33138 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -248,6 +248,10 @@ void cpu_check_irqs(CPUSPARCState *env)
uint32_t pil = env->pil_in |
(env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
+ /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
+ if (env->ivec_status & 0x20) {
+ return;
+ }
/* check if TM or SM in SOFTINT are set
setting these also causes interrupt 14 */
if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
@@ -275,7 +279,8 @@ void cpu_check_irqs(CPUSPARCState *env)
int old_interrupt = env->interrupt_index;
int new_interrupt = TT_EXTINT | i;
- if (env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt) {
+ if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
+ && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
"current %x >= pending %x\n",
env->tl, cpu_tsptr(env)->tt, new_interrupt);
commit 23cf96e1971f04f21ec4bb048df4d9e2e9933018
Author: Artyom Tarasenko <atar4qemu at gmail.com>
Date: Tue Apr 3 17:49:04 2012 +0200
Fix vector interrupt handling
Don't produce stray irq 5, don't overwrite ivec_data if still busy with
processing of the previous interrupt.
Signed-off-by: Artyom Tarasenko <atar4qemu at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 237e20c..50bc0d2 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -309,19 +309,22 @@ static void cpu_set_ivec_irq(void *opaque, int irq, int level)
CPUSPARCState *env = opaque;
if (level) {
- CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
- env->interrupt_index = TT_IVEC;
- env->pil_in |= 1 << 5;
- env->ivec_status |= 0x20;
- env->ivec_data[0] = (0x1f << 6) | irq;
- env->ivec_data[1] = 0;
- env->ivec_data[2] = 0;
- cpu_interrupt(env, CPU_INTERRUPT_HARD);
- } else {
- CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
- env->pil_in &= ~(1 << 5);
- env->ivec_status &= ~0x20;
- cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ if (!(env->ivec_status & 0x20)) {
+ CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
+ env->halted = 0;
+ env->interrupt_index = TT_IVEC;
+ env->ivec_status |= 0x20;
+ env->ivec_data[0] = (0x1f << 6) | irq;
+ env->ivec_data[1] = 0;
+ env->ivec_data[2] = 0;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+ } else {
+ if (env->ivec_status & 0x20) {
+ CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
+ env->ivec_status &= ~0x20;
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
}
}
commit b8ba6799f41cccd1e81ec2986f2f80fc916ef86f
Author: Andreas Färber <afaerber at suse.de>
Date: Mon Apr 2 14:00:43 2012 +0200
target-s390x: Update s390x_{tod,cpu}_timer() to use S390CPU
In place of CPUS390XState pass S390CPU as opaque from the new initfn.
cpu_interrupt() is anticipated to take a CPUState in the future.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Tested-by: Christian Borntraeger <borntraeger at de.ibm.com>
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 72ec349..f183213 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -60,8 +60,8 @@ static void s390_cpu_initfn(Object *obj)
env->tod_offset = TOD_UNIX_EPOCH +
(time2tod(mktimegm(&tm)) * 1000000000ULL);
env->tod_basetime = 0;
- env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, env);
- env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, env);
+ env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, cpu);
+ env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, cpu);
#endif
env->cpu_num = cpu_num++;
env->ext_index = -1;
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 6233f9a..209a696 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -53,7 +53,8 @@
#ifndef CONFIG_USER_ONLY
void s390x_tod_timer(void *opaque)
{
- CPUS390XState *env = opaque;
+ S390CPU *cpu = opaque;
+ CPUS390XState *env = &cpu->env;
env->pending_int |= INTERRUPT_TOD;
cpu_interrupt(env, CPU_INTERRUPT_HARD);
@@ -61,7 +62,8 @@ void s390x_tod_timer(void *opaque)
void s390x_cpu_timer(void *opaque)
{
- CPUS390XState *env = opaque;
+ S390CPU *cpu = opaque;
+ CPUS390XState *env = &cpu->env;
env->pending_int |= INTERRUPT_CPUTIMER;
cpu_interrupt(env, CPU_INTERRUPT_HARD);
commit 8f22e0df803697c11e8b10c90cc2e67df6e42884
Author: Andreas Färber <afaerber at suse.de>
Date: Mon Apr 2 13:56:29 2012 +0200
target-s390x: QOM'ify CPU init
Move code from cpu_s390x_init() into an initfn.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Tested-by: Christian Borntraeger <borntraeger at de.ibm.com>
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index cae0b18..72ec349 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -45,6 +45,30 @@ static void s390_cpu_reset(CPUState *s)
s390_add_running_cpu(env);
}
+static void s390_cpu_initfn(Object *obj)
+{
+ S390CPU *cpu = S390_CPU(obj);
+ CPUS390XState *env = &cpu->env;
+ static int cpu_num = 0;
+#if !defined(CONFIG_USER_ONLY)
+ struct tm tm;
+#endif
+
+ cpu_exec_init(env);
+#if !defined(CONFIG_USER_ONLY)
+ qemu_get_timedate(&tm, 0);
+ env->tod_offset = TOD_UNIX_EPOCH +
+ (time2tod(mktimegm(&tm)) * 1000000000ULL);
+ env->tod_basetime = 0;
+ env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, env);
+ env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, env);
+#endif
+ env->cpu_num = cpu_num++;
+ env->ext_index = -1;
+
+ cpu_reset(CPU(cpu));
+}
+
static void s390_cpu_class_init(ObjectClass *oc, void *data)
{
S390CPUClass *scc = S390_CPU_CLASS(oc);
@@ -58,6 +82,7 @@ static const TypeInfo s390_cpu_type_info = {
.name = TYPE_S390_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(S390CPU),
+ .instance_init = s390_cpu_initfn,
.abstract = false,
.class_size = sizeof(S390CPUClass),
.class_init = s390_cpu_class_init,
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index c6ee959..2f3f394 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -288,6 +288,9 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw
#ifndef CONFIG_USER_ONLY
+void s390x_tod_timer(void *opaque);
+void s390x_cpu_timer(void *opaque);
+
int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall);
#ifdef CONFIG_KVM
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index cd3e8f5..6233f9a 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -51,7 +51,7 @@
#endif
#ifndef CONFIG_USER_ONLY
-static void s390x_tod_timer(void *opaque)
+void s390x_tod_timer(void *opaque)
{
CPUS390XState *env = opaque;
@@ -59,7 +59,7 @@ static void s390x_tod_timer(void *opaque)
cpu_interrupt(env, CPU_INTERRUPT_HARD);
}
-static void s390x_cpu_timer(void *opaque)
+void s390x_cpu_timer(void *opaque)
{
CPUS390XState *env = opaque;
@@ -72,32 +72,17 @@ CPUS390XState *cpu_s390x_init(const char *cpu_model)
{
S390CPU *cpu;
CPUS390XState *env;
-#if !defined (CONFIG_USER_ONLY)
- struct tm tm;
-#endif
static int inited = 0;
- static int cpu_num = 0;
cpu = S390_CPU(object_new(TYPE_S390_CPU));
env = &cpu->env;
- cpu_exec_init(env);
+
if (tcg_enabled() && !inited) {
inited = 1;
s390x_translate_init();
}
-#if !defined(CONFIG_USER_ONLY)
- qemu_get_timedate(&tm, 0);
- env->tod_offset = TOD_UNIX_EPOCH +
- (time2tod(mktimegm(&tm)) * 1000000000ULL);
- env->tod_basetime = 0;
- env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, env);
- env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, env);
-#endif
env->cpu_model_str = cpu_model;
- env->cpu_num = cpu_num++;
- env->ext_index = -1;
- cpu_reset(CPU(cpu));
qemu_init_vcpu(env);
return env;
}
commit 1ac1a7499bcb44174735780e0bd0421a1ac7a323
Author: Andreas Färber <afaerber at suse.de>
Date: Mon Apr 2 13:31:59 2012 +0200
target-s390x: QOM'ify CPU reset
Move code from cpu_state_reset() to s390_cpu_reset().
Signed-off-by: Andreas Färber <afaerber at suse.de>
Tested-by: Christian Borntraeger <borntraeger at de.ibm.com>
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 94320f2..cae0b18 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -1,6 +1,8 @@
/*
* QEMU S/390 CPU
*
+ * Copyright (c) 2009 Ulrich Hecht
+ * Copyright (c) 2011 Alexander Graf
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This library is free software; you can redistribute it and/or
@@ -23,15 +25,24 @@
#include "qemu-timer.h"
+/* CPUClass::reset() */
static void s390_cpu_reset(CPUState *s)
{
S390CPU *cpu = S390_CPU(s);
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
CPUS390XState *env = &cpu->env;
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
scc->parent_reset(s);
- cpu_state_reset(env);
+ memset(env, 0, offsetof(CPUS390XState, breakpoints));
+ /* FIXME: reset vector? */
+ tlb_flush(env, 1);
+ s390_add_running_cpu(env);
}
static void s390_cpu_class_init(ObjectClass *oc, void *data)
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index ae57ab3..cd3e8f5 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -97,7 +97,7 @@ CPUS390XState *cpu_s390x_init(const char *cpu_model)
env->cpu_model_str = cpu_model;
env->cpu_num = cpu_num++;
env->ext_index = -1;
- cpu_state_reset(env);
+ cpu_reset(CPU(cpu));
qemu_init_vcpu(env);
return env;
}
@@ -123,15 +123,7 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw
void cpu_state_reset(CPUS390XState *env)
{
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- memset(env, 0, offsetof(CPUS390XState, breakpoints));
- /* FIXME: reset vector? */
- tlb_flush(env, 1);
- s390_add_running_cpu(env);
+ cpu_reset(ENV_GET_CPU(env));
}
#ifndef CONFIG_USER_ONLY
commit 29e4bcb26b80f975920508c83a9f24f29eb6bc1a
Author: Andreas Färber <afaerber at suse.de>
Date: Mon Apr 2 11:39:23 2012 +0200
target-s390x: QOM'ify CPU
Embed CPUS390XState as first member of S390CPU.
Since -cpu is being ignored, make TYPE_S390_CPU non-abstract.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Tested-by: Christian Borntraeger <borntraeger at de.ibm.com>
diff --git a/Makefile.target b/Makefile.target
index cff15f0..999a968 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -93,6 +93,7 @@ libobj-$(TARGET_SPARC64) += vis_helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-$(TARGET_ARM) += cpu.o
+libobj-$(TARGET_S390X) += cpu.o
ifeq ($(TARGET_BASE_ARCH), sparc)
libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
libobj-y += cpu_init.o
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
new file mode 100644
index 0000000..6fa55a8
--- /dev/null
+++ b/target-s390x/cpu-qom.h
@@ -0,0 +1,71 @@
+/*
+ * QEMU S/390 CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_S390_CPU_QOM_H
+#define QEMU_S390_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_S390_CPU "s390-cpu"
+
+#define S390_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(S390CPUClass, (klass), TYPE_S390_CPU)
+#define S390_CPU(obj) \
+ OBJECT_CHECK(S390CPU, (obj), TYPE_S390_CPU)
+#define S390_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(S390CPUClass, (obj), TYPE_S390_CPU)
+
+/**
+ * S390CPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An S/390 CPU model.
+ */
+typedef struct S390CPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} S390CPUClass;
+
+/**
+ * S390CPU:
+ * @env: #CPUS390XState.
+ *
+ * An S/390 CPU.
+ */
+typedef struct S390CPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUS390XState env;
+} S390CPU;
+
+static inline S390CPU *s390_env_get_cpu(CPUS390XState *env)
+{
+ return S390_CPU(container_of(env, S390CPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(s390_env_get_cpu(e))
+
+
+#endif
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
new file mode 100644
index 0000000..94320f2
--- /dev/null
+++ b/target-s390x/cpu.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU S/390 CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+#include "qemu-timer.h"
+
+
+static void s390_cpu_reset(CPUState *s)
+{
+ S390CPU *cpu = S390_CPU(s);
+ S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
+ CPUS390XState *env = &cpu->env;
+
+ scc->parent_reset(s);
+
+ cpu_state_reset(env);
+}
+
+static void s390_cpu_class_init(ObjectClass *oc, void *data)
+{
+ S390CPUClass *scc = S390_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(scc);
+
+ scc->parent_reset = cc->reset;
+ cc->reset = s390_cpu_reset;
+}
+
+static const TypeInfo s390_cpu_type_info = {
+ .name = TYPE_S390_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(S390CPU),
+ .abstract = false,
+ .class_size = sizeof(S390CPUClass),
+ .class_init = s390_cpu_class_init,
+};
+
+static void s390_cpu_register_types(void)
+{
+ type_register_static(&s390_cpu_type_info);
+}
+
+type_init(s390_cpu_register_types)
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index ea849fc..c6ee959 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -991,4 +991,6 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb)
env->psw.addr = tb->pc;
}
+#include "cpu-qom.h"
+
#endif
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 44d5048..ae57ab3 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -70,6 +70,7 @@ static void s390x_cpu_timer(void *opaque)
CPUS390XState *cpu_s390x_init(const char *cpu_model)
{
+ S390CPU *cpu;
CPUS390XState *env;
#if !defined (CONFIG_USER_ONLY)
struct tm tm;
@@ -77,7 +78,8 @@ CPUS390XState *cpu_s390x_init(const char *cpu_model)
static int inited = 0;
static int cpu_num = 0;
- env = g_malloc0(sizeof(CPUS390XState));
+ cpu = S390_CPU(object_new(TYPE_S390_CPU));
+ env = &cpu->env;
cpu_exec_init(env);
if (tcg_enabled() && !inited) {
inited = 1;
commit 53fbf7b5391c76cc474d469bfed6a69a1243f4de
Author: Anthony PERARD <anthony.perard at citrix.com>
Date: Mon Apr 2 16:10:39 2012 +0100
make: fix clean rule by removing build file in qom/
Make clean does not clean the 'qom' directory, leaving *.o and *.d files. This
patch fixes this.
Signed-off-by: Anthony PERARD <anthony.perard at citrix.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/Makefile b/Makefile
index 35c7a2a..a78f53d 100644
--- a/Makefile
+++ b/Makefile
@@ -217,6 +217,7 @@ clean:
rm -f *.o *.d *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
rm -Rf .libs
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
+ rm -f qom/*.o qom/*.d
rm -f qemu-img-cmds.h
rm -f trace/*.o trace/*.d
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
commit c9a2e37c7d70e1b1f11997f7ecab202393bff9fc
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Mon Apr 2 14:49:49 2012 +0200
configure: Link qga against UST tracing related libraries
Signed-off-by: Harsh Prateek Bora <harsh at linux.vnet.ibm.com>
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/configure b/configure
index 319355b..520bd93 100755
--- a/configure
+++ b/configure
@@ -2673,6 +2673,7 @@ int main(void) { return 0; }
EOF
if compile_prog "" "" ; then
LIBS="-lust -lurcu-bp $LIBS"
+ libs_qga="-lust -lurcu-bp $libs_qga"
else
echo
echo "Error: Trace backend 'ust' missing libust header files"
commit 94b4fefae6aa8ee7739b2b9ad6ef14a07baf78be
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Mon Apr 2 14:49:44 2012 +0200
configure: Link QEMU against 'liburcu-bp'
This library is needed when using 'ust/tracepoint.h'.
Signed-off-by: Harsh Prateek Bora <harsh at linux.vnet.ibm.com>
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/configure b/configure
index c0a542b..319355b 100755
--- a/configure
+++ b/configure
@@ -2672,7 +2672,7 @@ if test "$trace_backend" = "ust"; then
int main(void) { return 0; }
EOF
if compile_prog "" "" ; then
- LIBS="-lust $LIBS"
+ LIBS="-lust -lurcu-bp $LIBS"
else
echo
echo "Error: Trace backend 'ust' missing libust header files"
commit a92433afcc1e48b0ba7a014bb6d2f0a7cd416a31
Author: Frediano Ziglio <freddy77 at gmail.com>
Date: Sat Mar 31 19:32:14 2012 +0100
main-loop: make qemu_event_handle static
Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/main-loop.c b/main-loop.c
index db23de0..fc738d1 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -164,7 +164,7 @@ static int qemu_signal_init(void)
#else /* _WIN32 */
-HANDLE qemu_event_handle = NULL;
+static HANDLE qemu_event_handle = NULL;
static void dummy_event_handler(void *opaque)
{
commit fb7c8e8a2d3ac99c9310a01d17a2b46584320bc9
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Mar 31 17:34:41 2012 +0200
block/curl: Replace usleep by g_usleep
The function usleep is not available for all supported platforms:
at least some versions of MinGW don't support it.
usleep was also declared obsolete by POSIX.1-2001.
The function g_usleep is part of glib2.0, so it is available for
all supported platforms.
Using nanosleep would also be possible but needs more code.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/block/curl.c b/block/curl.c
index e9102e3..a909eca 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -282,7 +282,7 @@ static CURLState *curl_init_state(BDRVCURLState *s)
break;
}
if (!state) {
- usleep(100);
+ g_usleep(100);
curl_multi_do(s);
}
} while(!state);
commit 3f97fd851cf7b16b822c2c366e02708070f713bb
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Mar 31 17:11:31 2012 +0200
qtest: Add missing GCC_FMT_ATTR
gcc reports an error when the code is compiled with -Wmissing-format-attribute.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/qtest.c b/qtest.c
index daeabb7..18afcd9 100644
--- a/qtest.c
+++ b/qtest.c
@@ -156,7 +156,8 @@ static void qtest_send_prefix(CharDriverState *chr)
tv.tv_sec, tv.tv_usec);
}
-static void qtest_send(CharDriverState *chr, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
+ const char *fmt, ...)
{
va_list ap;
char buffer[1024];
commit 6cec29c4a0338bfd96dec42cce51c9c447facb23
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Wed Mar 28 20:56:38 2012 +0200
w32: Undefine error constants before their redefinition
Avoids lots of warnings.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/qemu_socket.h b/qemu_socket.h
index fe4cf6c..51ad210 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -8,7 +8,9 @@
#include <ws2tcpip.h>
#define socket_error() WSAGetLastError()
+#undef EWOULDBLOCK
#undef EINTR
+#undef EINPROGRESS
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EINTR WSAEINTR
#define EINPROGRESS WSAEINPROGRESS
commit 368542b8356038593c4d394d87ee086ef65a6da3
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Tue Mar 27 08:26:18 2012 +0100
configure: fix mingw32 libs_qga typo
It's typical to prepend or append parameters to an argument string so
that other places in ./configure can add parameters without clobbering
the string. In the mingw32 libs_qga case there is a typo "$lib_qga"
instead of "$libs_qga".
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Andreas Färber <afaerber at suse.de>
diff --git a/configure b/configure
index 4b3adc9..c0a542b 100755
--- a/configure
+++ b/configure
@@ -526,7 +526,7 @@ EOF
bindir="\${prefix}"
sysconfdir="\${prefix}"
confsuffix=""
- libs_qga="-lws2_32 -lwinmm -lpowrprof $lib_qga"
+ libs_qga="-lws2_32 -lwinmm -lpowrprof $libs_qga"
fi
werror=""
commit f05f6b4adb4db3affb0cdd17383b0a7e905e66e1
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Mar 28 16:34:12 2012 +0200
qdev: put all devices under /machine
Avoid cluttering too much the QOM root.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 9017565..179d9a6 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -276,7 +276,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
b = pci_bus_new(&s->busdev.qdev, NULL, pci_address_space,
address_space_io, 0);
s->bus = b;
- object_property_add_child(object_get_root(), "i440fx", OBJECT(dev), NULL);
+ object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
qdev_init_nofail(dev);
d = pci_create_simple(b, 0, device_name);
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 86c9336..9d8e659 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -615,7 +615,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
sys = sysbus_from_qdev(dev);
pcihost = DO_UPCAST(PCIHostState, busdev, sys);
pcihost->address_space = get_system_memory();
- object_property_add_child(object_get_root(), "raven", OBJECT(dev), NULL);
+ object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL);
qdev_init_nofail(dev);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
if (pci_bus == NULL) {
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 031cb83..4783366 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -180,7 +180,7 @@ static Object *qdev_get_peripheral(void)
static Object *dev;
if (dev == NULL) {
- dev = container_get("/peripheral");
+ dev = container_get("/machine/peripheral");
}
return dev;
@@ -191,7 +191,7 @@ static Object *qdev_get_peripheral_anon(void)
static Object *dev;
if (dev == NULL) {
- dev = container_get("/peripheral-anon");
+ dev = container_get("/machine/peripheral-anon");
}
return dev;
diff --git a/hw/qdev.c b/hw/qdev.c
index f5c716e..0d3c0fc 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -157,7 +157,7 @@ int qdev_init(DeviceState *dev)
static int unattached_count = 0;
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
- object_property_add_child(container_get("/unattached"), name,
+ object_property_add_child(container_get("/machine/unattached"), name,
OBJECT(dev), NULL);
g_free(name);
}
@@ -668,6 +668,17 @@ void device_reset(DeviceState *dev)
}
}
+Object *qdev_get_machine(void)
+{
+ static Object *dev;
+
+ if (dev == NULL) {
+ dev = container_get("/machine");
+ }
+
+ return dev;
+}
+
static TypeInfo device_type_info = {
.name = TYPE_DEVICE,
.parent = TYPE_OBJECT,
diff --git a/hw/qdev.h b/hw/qdev.h
index 9cc3f98..a8df42f 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -349,6 +349,8 @@ BusInfo *qdev_get_bus_info(DeviceState *dev);
Property *qdev_get_props(DeviceState *dev);
+Object *qdev_get_machine(void);
+
/* FIXME: make this a link<> */
void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
commit da57febfed7bad11be79f047b59719c38abd0712
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 27 18:38:47 2012 +0200
qdev: give all devices a canonical path
A strong limitation of QOM right now is that unconverted ports
(e.g. all...) do not give a canonical path to devices that are
part of the board. This in turn makes it impossible to replace
PROP_PTR with a QOM link for example.
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/qdev.c b/hw/qdev.c
index ee21d90..f5c716e 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -113,14 +113,14 @@ DeviceState *qdev_create(BusState *bus, const char *name)
return dev;
}
-DeviceState *qdev_try_create(BusState *bus, const char *name)
+DeviceState *qdev_try_create(BusState *bus, const char *type)
{
DeviceState *dev;
- if (object_class_by_name(name) == NULL) {
+ if (object_class_by_name(type) == NULL) {
return NULL;
}
- dev = DEVICE(object_new(name));
+ dev = DEVICE(object_new(type));
if (!dev) {
return NULL;
}
@@ -152,6 +152,16 @@ int qdev_init(DeviceState *dev)
qdev_free(dev);
return rc;
}
+
+ if (!OBJECT(dev)->parent) {
+ static int unattached_count = 0;
+ gchar *name = g_strdup_printf("device[%d]", unattached_count++);
+
+ object_property_add_child(container_get("/unattached"), name,
+ OBJECT(dev), NULL);
+ g_free(name);
+ }
+
if (qdev_get_vmsd(dev)) {
vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
dev->instance_id_alias,
commit f424d5c4c9de67b56594384eac3c08dc33de9344
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 27 18:38:46 2012 +0200
qdev: add children before qdev_init
We want the composition tree to to be in order by the time we call
qdev_init, so that a single set of the toplevel realize property can
propagate all the way down the composition tree.
This is not the case so far. Unfortunately, this is incompatible
with calling qdev_init in the constructor wrappers for devices,
so for now we need to unattach some devices that are created through
those wrappers. This will be fixed by removing qdev_init and instead
setting the toplevel realize property after machine init.
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index ec5118f..fadca4c 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -149,7 +149,6 @@ static void pc_init1(MemoryRegion *system_memory,
MemoryRegion *ram_memory;
MemoryRegion *pci_memory;
MemoryRegion *rom_memory;
- DeviceState *dev;
pc_cpus_init(cpu_model);
@@ -227,11 +226,7 @@ static void pc_init1(MemoryRegion *system_memory,
pc_register_ferr_irq(gsi[13]);
- dev = pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
- if (dev) {
- object_property_add_child(object_get_root(), "vga", OBJECT(dev), NULL);
- }
-
+ pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
if (xen_enabled()) {
pci_create_simple(pci_bus, -1, "xen-platform");
}
@@ -258,17 +253,6 @@ static void pc_init1(MemoryRegion *system_memory,
}
idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
-
- /* FIXME there's some major spaghetti here. Somehow we create the
- * devices on the PIIX before we actually create it. We create the
- * PIIX3 deep in the recess of the i440fx creation too and then lose
- * the DeviceState.
- *
- * For now, let's "fix" this by making judicious use of paths. This
- * is not generally the right way to do this.
- */
- object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
- "rtc", (Object *)rtc_state, NULL);
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index e0268fe..9017565 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -276,8 +276,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
b = pci_bus_new(&s->busdev.qdev, NULL, pci_address_space,
address_space_io, 0);
s->bus = b;
- qdev_init_nofail(dev);
object_property_add_child(object_get_root(), "i440fx", OBJECT(dev), NULL);
+ qdev_init_nofail(dev);
d = pci_create_simple(b, 0, device_name);
*pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
@@ -316,7 +316,6 @@ static PCIBus *i440fx_common_init(const char *device_name,
pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
PIIX_NUM_PIRQS);
}
- object_property_add_child(OBJECT(dev), "piix3", OBJECT(piix3), NULL);
piix3->pic = pic;
*isa_bus = DO_UPCAST(ISABus, qbus,
qdev_get_child_bus(&piix3->dev.qdev, "isa.0"));
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 06d589d..86c9336 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -615,8 +615,8 @@ static void ppc_prep_init (ram_addr_t ram_size,
sys = sysbus_from_qdev(dev);
pcihost = DO_UPCAST(PCIHostState, busdev, sys);
pcihost->address_space = get_system_memory();
- qdev_init_nofail(dev);
object_property_add_child(object_get_root(), "raven", OBJECT(dev), NULL);
+ qdev_init_nofail(dev);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
if (pci_bus == NULL) {
fprintf(stderr, "Couldn't create PCI host controller.\n");
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 2e82962..031cb83 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -458,10 +458,6 @@ DeviceState *qdev_device_add(QemuOpts *opts)
qdev_free(qdev);
return NULL;
}
- if (qdev_init(qdev) < 0) {
- qerror_report(QERR_DEVICE_INIT_FAILED, driver);
- return NULL;
- }
if (qdev->id) {
object_property_add_child(qdev_get_peripheral(), qdev->id,
OBJECT(qdev), NULL);
@@ -472,6 +468,10 @@ DeviceState *qdev_device_add(QemuOpts *opts)
OBJECT(qdev), NULL);
g_free(name);
}
+ if (qdev_init(qdev) < 0) {
+ qerror_report(QERR_DEVICE_INIT_FAILED, driver);
+ return NULL;
+ }
qdev->opts = opts;
return qdev;
}
commit a612b2a6635fa1a3a29a8bcf41b31f1f3fae1110
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 27 18:38:45 2012 +0200
qom: add container_get
This is QOM "mkdir -p". It is useful when referring to
container objects such as "/machine".
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index a310cc7..2e82962 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -180,9 +180,7 @@ static Object *qdev_get_peripheral(void)
static Object *dev;
if (dev == NULL) {
- dev = object_new("container");
- object_property_add_child(object_get_root(), "peripheral",
- OBJECT(dev), NULL);
+ dev = container_get("/peripheral");
}
return dev;
@@ -193,9 +191,7 @@ static Object *qdev_get_peripheral_anon(void)
static Object *dev;
if (dev == NULL) {
- dev = object_new("container");
- object_property_add_child(object_get_root(), "peripheral-anon",
- OBJECT(dev), NULL);
+ dev = container_get("/peripheral-anon");
}
return dev;
diff --git a/include/qemu/object.h b/include/qemu/object.h
index e8fc126..a675937 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -837,6 +837,18 @@ Object *object_resolve_path_type(const char *path, const char *typename,
bool *ambiguous);
/**
+ * object_resolve_path_component:
+ * @parent: the object in which to resolve the path
+ * @part: the component to resolve.
+ *
+ * This is similar to object_resolve_path with an absolute path, but it
+ * only resolves one element (@part) and takes the others from @parent.
+ *
+ * Returns: The resolved object or NULL on path lookup failure.
+ */
+Object *object_resolve_path_component(Object *parent, gchar *part);
+
+/**
* object_property_add_child:
* @obj: the object to add a property to
* @name: the name of the property
@@ -891,4 +903,16 @@ void object_property_add_str(Object *obj, const char *name,
void (*set)(Object *, const char *, struct Error **),
struct Error **errp);
+/**
+ * container_get:
+ * @path: path to the container
+ *
+ * Return a container object whose path is @path. Create more containers
+ * along the path if necessary.
+ *
+ * Returns: the container object.
+ */
+Object *container_get(const char *path);
+
+
#endif
diff --git a/qom/container.c b/qom/container.c
index f107208..67e9e8a 100644
--- a/qom/container.c
+++ b/qom/container.c
@@ -12,6 +12,7 @@
#include "qemu/object.h"
#include "module.h"
+#include <assert.h>
static TypeInfo container_info = {
.name = "container",
@@ -24,4 +25,26 @@ static void container_register_types(void)
type_register_static(&container_info);
}
+Object *container_get(const char *path)
+{
+ Object *obj, *child;
+ gchar **parts;
+ int i;
+
+ parts = g_strsplit(path, "/", 0);
+ assert(parts != NULL && parts[0] != NULL && !parts[0][0]);
+ obj = object_get_root();
+
+ for (i = 1; parts[i] != NULL; i++, obj = child) {
+ child = object_resolve_path_component(obj, parts[i]);
+ if (!child) {
+ child = object_new("container");
+ object_property_add_child(obj, parts[i], child, NULL);
+ }
+ }
+
+ return obj;
+}
+
+
type_init(container_register_types)
diff --git a/qom/object.c b/qom/object.c
index 9cd9506..e721fc2 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1022,12 +1022,27 @@ gchar *object_get_canonical_path(Object *obj)
return newpath;
}
+Object *object_resolve_path_component(Object *parent, gchar *part)
+{
+ ObjectProperty *prop = object_property_find(parent, part);
+ if (prop == NULL) {
+ return NULL;
+ }
+
+ if (strstart(prop->type, "link<", NULL)) {
+ return *(Object **)prop->opaque;
+ } else if (strstart(prop->type, "child<", NULL)) {
+ return prop->opaque;
+ } else {
+ return NULL;
+ }
+}
+
static Object *object_resolve_abs_path(Object *parent,
gchar **parts,
const char *typename,
int index)
{
- ObjectProperty *prop;
Object *child;
if (parts[index] == NULL) {
@@ -1038,21 +1053,7 @@ static Object *object_resolve_abs_path(Object *parent,
return object_resolve_abs_path(parent, parts, typename, index + 1);
}
- prop = object_property_find(parent, parts[index]);
- if (prop == NULL) {
- return NULL;
- }
-
- child = NULL;
- if (strstart(prop->type, "link<", NULL)) {
- Object **pchild = prop->opaque;
- if (*pchild) {
- child = *pchild;
- }
- } else if (strstart(prop->type, "child<", NULL)) {
- child = prop->opaque;
- }
-
+ child = object_resolve_path_component(parent, parts[index]);
if (!child) {
return NULL;
}
commit cefc898806e0346eef87d15ddaac9475b57b7d84
Merge: aba8e41... 8607301...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 2 09:46:45 2012 -0500
Merge remote-tracking branch 'kiszka/queues/slirp' into staging
* kiszka/queues/slirp:
slirp: Signal free input buffer space to io-thread
w32/slirp: Undefine error constants before their redefinition
slirp: use socket_set_nonblock
slirp: clean up conflicts with system headers
commit aba8e41e8666e4c0287cef1f6298985d4e03211d
Merge: dfe844c... 703e01e...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 2 09:44:35 2012 -0500
Merge remote-tracking branch 'stefanha/tracing' into staging
* stefanha/tracing:
tracetool: dtrace: handle in and next reserved words
tracetool: dtrace disabled-events fix
Makefile.target: code stp dependency on trace-events
commit dfe844c9043815497b6472bfaf470b0f8d2e7312
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Sun Apr 1 14:18:30 2012 -0500
serial: clear LSR.TEMT when populating the TSR
We never actually clear the TEMT (transmit sending register empty) flag when
populating the TSR. We set the flag, but since it's never cleared, setting it
is sort of pointless..
I found this with a unit test case.
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/serial.c b/hw/serial.c
index b499bca..a421d1e 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -332,6 +332,7 @@ static void serial_xmit(void *opaque)
} else {
s->tsr = s->thr;
s->lsr |= UART_LSR_THRE;
+ s->lsr &= ~UART_LSR_TEMT;
}
}
commit 67c5322d7000fd105a926eec44bc1765b7d70bdd
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Sun Apr 1 14:03:21 2012 -0500
serial: fix retry logic
I'm not sure if the retry logic has ever worked when not using FIFO mode. I
found this while writing a test case although code inspection confirms it is
definitely broken.
The TSR retry logic will never actually happen because it is guarded by an
'if (s->tsr_rety > 0)' but this is the only place that can ever make the
variable greater than zero. That effectively makes the retry logic an 'if (0)'.
I believe this is a typo and the intention was >= 0. Once this is fixed though,
I see double transmits with my test case. This is because in the non FIFO
case, serial_xmit may get invoked while LSR.THRE is still high because the
character was processed but the retransmit timer was still active.
We can handle this by simply checking for LSR.THRE and returning early. It's
possible that the FIFO paths also need some attention.
Cc: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/serial.c b/hw/serial.c
index c0ee55d..b499bca 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -327,6 +327,8 @@ static void serial_xmit(void *opaque)
s->tsr = fifo_get(s,XMIT_FIFO);
if (!s->xmit_fifo.count)
s->lsr |= UART_LSR_THRE;
+ } else if ((s->lsr & UART_LSR_THRE)) {
+ return;
} else {
s->tsr = s->thr;
s->lsr |= UART_LSR_THRE;
@@ -337,7 +339,7 @@ static void serial_xmit(void *opaque)
/* in loopback mode, say that we just received a char */
serial_receive1(s, &s->tsr, 1);
} else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) {
- if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
+ if ((s->tsr_retry >= 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
s->tsr_retry++;
qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time);
return;
commit 6e92466a7c16bc5a33a674b76964f4b1ac7fa44d
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Fri Mar 30 14:04:04 2012 -0500
qtest: use qemu_gettimeofday()
On linux, qemu_timeval will always be two long ints. On windows, we use our
own struct definition. This should fix win64.
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qtest.c b/qtest.c
index cd7186c..daeabb7 100644
--- a/qtest.c
+++ b/qtest.c
@@ -31,7 +31,7 @@ static FILE *qtest_log_fp;
static CharDriverState *qtest_chr;
static GString *inbuf;
static int irq_levels[MAX_IRQ];
-static struct timeval start_time;
+static qemu_timeval start_time;
static bool qtest_opened;
#define FMT_timeval "%ld.%06ld"
@@ -132,9 +132,9 @@ static int hex2nib(char ch)
}
}
-static void qtest_get_time(struct timeval *tv)
+static void qtest_get_time(qemu_timeval *tv)
{
- gettimeofday(tv, NULL);
+ qemu_gettimeofday(tv);
tv->tv_sec -= start_time.tv_sec;
tv->tv_usec -= start_time.tv_usec;
if (tv->tv_usec < 0) {
@@ -145,7 +145,7 @@ static void qtest_get_time(struct timeval *tv)
static void qtest_send_prefix(CharDriverState *chr)
{
- struct timeval tv;
+ qemu_timeval tv;
if (!qtest_log_fp || !qtest_opened) {
return;
@@ -195,7 +195,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
command = words[0];
if (qtest_log_fp) {
- struct timeval tv;
+ qemu_timeval tv;
int i;
qtest_get_time(&tv);
@@ -394,7 +394,7 @@ static void qtest_event(void *opaque, int event)
for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
irq_levels[i] = 0;
}
- gettimeofday(&start_time, NULL);
+ qemu_gettimeofday(&start_time);
qtest_opened = true;
if (qtest_log_fp) {
fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
@@ -404,7 +404,7 @@ static void qtest_event(void *opaque, int event)
case CHR_EVENT_CLOSED:
qtest_opened = false;
if (qtest_log_fp) {
- struct timeval tv;
+ qemu_timeval tv;
qtest_get_time(&tv);
fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
tv.tv_sec, tv.tv_usec);
commit a3b6181e42ef5713c684283c0187abaa11ef1eaf
Author: Michael Walle <michael at walle.cc>
Date: Sat Mar 31 19:55:25 2012 +0200
milkymist-vgafb: add missing register
This bug existed since the first commit. Fortunately, the affected
registers have no functionality in qemu. This will only prevent the
following warning:
milkymist_vgafb: write access to unknown register 0x00000034
Signed-off-by: Michael Walle <michael at walle.cc>
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
index 69afd72..cd4365d 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -2,7 +2,7 @@
/*
* QEMU model of the Milkymist VGA framebuffer.
*
- * Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ * Copyright (c) 2010-2012 Michael Walle <michael at walle.cc>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -54,6 +54,7 @@ enum {
R_BASEADDRESS,
R_BASEADDRESS_ACT,
R_BURST_COUNT,
+ R_DDC,
R_SOURCE_CLOCK,
R_MAX
};
@@ -173,6 +174,7 @@ static uint64_t vgafb_read(void *opaque, target_phys_addr_t addr,
case R_VSCAN:
case R_BASEADDRESS:
case R_BURST_COUNT:
+ case R_DDC:
case R_SOURCE_CLOCK:
r = s->regs[addr];
break;
@@ -211,6 +213,7 @@ static void vgafb_write(void *opaque, target_phys_addr_t addr, uint64_t value,
case R_VSYNC_END:
case R_VSCAN:
case R_BURST_COUNT:
+ case R_DDC:
case R_SOURCE_CLOCK:
s->regs[addr] = value;
break;
commit 79368f4984eefcbed5d714c6131e58fd71178030
Author: Michael Walle <michael at walle.cc>
Date: Sat Mar 31 19:54:20 2012 +0200
target-lm32: add simple disassembler
Because binutils disassembler is based on libopcode, this is a rewrite from
scratch.
Signed-off-by: Michael Walle <michael at walle.cc>
diff --git a/Makefile.objs b/Makefile.objs
index e9842b0..f308b57 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -365,6 +365,7 @@ libdis-$(CONFIG_PPC_DIS) += ppc-dis.o
libdis-$(CONFIG_S390_DIS) += s390-dis.o
libdis-$(CONFIG_SH4_DIS) += sh4-dis.o
libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
+libdis-$(CONFIG_LM32_DIS) += lm32-dis.o
######################################################################
# trace
diff --git a/configure b/configure
index 4ef5ec6..4b3adc9 100755
--- a/configure
+++ b/configure
@@ -3770,6 +3770,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
echo "CONFIG_IA64_DIS=y" >> $config_target_mak
echo "CONFIG_IA64_DIS=y" >> $libdis_config_mak
;;
+ lm32)
+ echo "CONFIG_LM32_DIS=y" >> $config_target_mak
+ echo "CONFIG_LM32_DIS=y" >> $libdis_config_mak
+ ;;
m68k)
echo "CONFIG_M68K_DIS=y" >> $config_target_mak
echo "CONFIG_M68K_DIS=y" >> $libdis_config_mak
diff --git a/dis-asm.h b/dis-asm.h
index 4f15fad..3944b3c 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -221,6 +221,8 @@ enum bfd_architecture
bfd_arch_ia64, /* HP/Intel ia64 */
#define bfd_mach_ia64_elf64 64
#define bfd_mach_ia64_elf32 32
+ bfd_arch_lm32, /* Lattice Mico32 */
+#define bfd_mach_lm32 1
bfd_arch_last
};
#define bfd_mach_s390_31 31
@@ -404,6 +406,7 @@ int print_insn_crisv32 (bfd_vma, disassemble_info*);
int print_insn_crisv10 (bfd_vma, disassemble_info*);
int print_insn_microblaze (bfd_vma, disassemble_info*);
int print_insn_ia64 (bfd_vma, disassemble_info*);
+int print_insn_lm32 (bfd_vma, disassemble_info*);
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
diff --git a/disas.c b/disas.c
index 4945c44..9485824 100644
--- a/disas.c
+++ b/disas.c
@@ -220,6 +220,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
#elif defined(TARGET_MICROBLAZE)
disasm_info.mach = bfd_arch_microblaze;
print_insn = print_insn_microblaze;
+#elif defined(TARGET_LM32)
+ disasm_info.mach = bfd_mach_lm32;
+ print_insn = print_insn_lm32;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
@@ -421,6 +424,9 @@ void monitor_disas(Monitor *mon, CPUArchState *env,
#elif defined(TARGET_S390X)
disasm_info.mach = bfd_mach_s390_64;
print_insn = print_insn_s390;
+#elif defined(TARGET_LM32)
+ disasm_info.mach = bfd_mach_lm32;
+ print_insn = print_insn_lm32;
#else
monitor_printf(mon, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);
diff --git a/lm32-dis.c b/lm32-dis.c
new file mode 100644
index 0000000..709ed32
--- /dev/null
+++ b/lm32-dis.c
@@ -0,0 +1,361 @@
+/*
+ * Simple LatticeMico32 disassembler.
+ *
+ * Copyright (c) 2012 Michael Walle <michael at walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include "dis-asm.h"
+
+typedef enum {
+ LM32_OP_SRUI = 0, LM32_OP_NORI, LM32_OP_MULI, LM32_OP_SH, LM32_OP_LB,
+ LM32_OP_SRI, LM32_OP_XORI, LM32_OP_LH, LM32_OP_ANDI, LM32_OP_XNORI,
+ LM32_OP_LW, LM32_OP_LHU, LM32_OP_SB, LM32_OP_ADDI, LM32_OP_ORI,
+ LM32_OP_SLI, LM32_OP_LBU, LM32_OP_BE, LM32_OP_BG, LM32_OP_BGE,
+ LM32_OP_BGEU, LM32_OP_BGU, LM32_OP_SW, LM32_OP_BNE, LM32_OP_ANDHI,
+ LM32_OP_CMPEI, LM32_OP_CMPGI, LM32_OP_CMPGEI, LM32_OP_CMPGEUI,
+ LM32_OP_CMPGUI, LM32_OP_ORHI, LM32_OP_CMPNEI, LM32_OP_SRU, LM32_OP_NOR,
+ LM32_OP_MUL, LM32_OP_DIVU, LM32_OP_RCSR, LM32_OP_SR, LM32_OP_XOR,
+ LM32_OP_ILL0, LM32_OP_AND, LM32_OP_XNOR, LM32_OP_ILL1, LM32_OP_SCALL,
+ LM32_OP_SEXTB, LM32_OP_ADD, LM32_OP_OR, LM32_OP_SL, LM32_OP_B,
+ LM32_OP_MODU, LM32_OP_SUB, LM32_OP_ILL2, LM32_OP_WCSR, LM32_OP_ILL3,
+ LM32_OP_CALL, LM32_OP_SEXTH, LM32_OP_BI, LM32_OP_CMPE, LM32_OP_CMPG,
+ LM32_OP_CMPGE, LM32_OP_CMPGEU, LM32_OP_CMPGU, LM32_OP_CALLI, LM32_OP_CMPNE,
+} Lm32Opcode;
+
+typedef enum {
+ FMT_INVALID = 0, FMT_RRI5, FMT_RRI16, FMT_IMM26, FMT_LOAD, FMT_STORE,
+ FMT_RRR, FMT_R, FMT_RNR, FMT_CRN, FMT_CNR, FMT_BREAK,
+} Lm32OpcodeFmt;
+
+typedef enum {
+ LM32_CSR_IE = 0, LM32_CSR_IM, LM32_CSR_IP, LM32_CSR_ICC, LM32_CSR_DCC,
+ LM32_CSR_CC, LM32_CSR_CFG, LM32_CSR_EBA, LM32_CSR_DC, LM32_CSR_DEBA,
+ LM32_CSR_CFG2, LM32_CSR_JTX = 0xe, LM32_CSR_JRX, LM32_CSR_BP0,
+ LM32_CSR_BP1, LM32_CSR_BP2, LM32_CSR_BP3, LM32_CSR_WP0 = 0x18,
+ LM32_CSR_WP1, LM32_CSR_WP2, LM32_CSR_WP3,
+} Lm32CsrNum;
+
+typedef struct {
+ int csr;
+ const char *name;
+} Lm32CsrInfo;
+
+static const Lm32CsrInfo lm32_csr_info[] = {
+ {LM32_CSR_IE, "ie", },
+ {LM32_CSR_IM, "im", },
+ {LM32_CSR_IP, "ip", },
+ {LM32_CSR_ICC, "icc", },
+ {LM32_CSR_DCC, "dcc", },
+ {LM32_CSR_CC, "cc", },
+ {LM32_CSR_CFG, "cfg", },
+ {LM32_CSR_EBA, "eba", },
+ {LM32_CSR_DC, "dc", },
+ {LM32_CSR_DEBA, "deba", },
+ {LM32_CSR_CFG2, "cfg2", },
+ {LM32_CSR_JTX, "jtx", },
+ {LM32_CSR_JRX, "jrx", },
+ {LM32_CSR_BP0, "bp0", },
+ {LM32_CSR_BP1, "bp1", },
+ {LM32_CSR_BP2, "bp2", },
+ {LM32_CSR_BP3, "bp3", },
+ {LM32_CSR_WP0, "wp0", },
+ {LM32_CSR_WP1, "wp1", },
+ {LM32_CSR_WP2, "wp2", },
+ {LM32_CSR_WP3, "wp3", },
+};
+
+static const Lm32CsrInfo *find_csr_info(int csr)
+{
+ const Lm32CsrInfo *info;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lm32_csr_info); i++) {
+ info = &lm32_csr_info[i];
+ if (csr == info->csr) {
+ return info;
+ }
+ }
+
+ return NULL;
+}
+
+typedef struct {
+ int reg;
+ const char *name;
+} Lm32RegInfo;
+
+typedef enum {
+ LM32_REG_R0 = 0, LM32_REG_R1, LM32_REG_R2, LM32_REG_R3, LM32_REG_R4,
+ LM32_REG_R5, LM32_REG_R6, LM32_REG_R7, LM32_REG_R8, LM32_REG_R9,
+ LM32_REG_R10, LM32_REG_R11, LM32_REG_R12, LM32_REG_R13, LM32_REG_R14,
+ LM32_REG_R15, LM32_REG_R16, LM32_REG_R17, LM32_REG_R18, LM32_REG_R19,
+ LM32_REG_R20, LM32_REG_R21, LM32_REG_R22, LM32_REG_R23, LM32_REG_R24,
+ LM32_REG_R25, LM32_REG_GP, LM32_REG_FP, LM32_REG_SP, LM32_REG_RA,
+ LM32_REG_EA, LM32_REG_BA,
+} Lm32RegNum;
+
+static const Lm32RegInfo lm32_reg_info[] = {
+ {LM32_REG_R0, "r0", },
+ {LM32_REG_R1, "r1", },
+ {LM32_REG_R2, "r2", },
+ {LM32_REG_R3, "r3", },
+ {LM32_REG_R4, "r4", },
+ {LM32_REG_R5, "r5", },
+ {LM32_REG_R6, "r6", },
+ {LM32_REG_R7, "r7", },
+ {LM32_REG_R8, "r8", },
+ {LM32_REG_R9, "r9", },
+ {LM32_REG_R10, "r10", },
+ {LM32_REG_R11, "r11", },
+ {LM32_REG_R12, "r12", },
+ {LM32_REG_R13, "r13", },
+ {LM32_REG_R14, "r14", },
+ {LM32_REG_R15, "r15", },
+ {LM32_REG_R16, "r16", },
+ {LM32_REG_R17, "r17", },
+ {LM32_REG_R18, "r18", },
+ {LM32_REG_R19, "r19", },
+ {LM32_REG_R20, "r20", },
+ {LM32_REG_R21, "r21", },
+ {LM32_REG_R22, "r22", },
+ {LM32_REG_R23, "r23", },
+ {LM32_REG_R24, "r24", },
+ {LM32_REG_R25, "r25", },
+ {LM32_REG_GP, "gp", },
+ {LM32_REG_FP, "fp", },
+ {LM32_REG_SP, "sp", },
+ {LM32_REG_RA, "ra", },
+ {LM32_REG_EA, "ea", },
+ {LM32_REG_BA, "ba", },
+};
+
+static const Lm32RegInfo *find_reg_info(int reg)
+{
+ assert(ARRAY_SIZE(lm32_reg_info) == 32);
+ return &lm32_reg_info[reg & 0x1f];
+}
+
+typedef struct {
+ struct {
+ uint32_t code;
+ uint32_t mask;
+ } op;
+ const char *name;
+ const char *args_fmt;
+} Lm32OpcodeInfo;
+
+static const Lm32OpcodeInfo lm32_opcode_info[] = {
+ /* pseudo instructions */
+ {{0x34000000, 0xffffffff}, "nop", NULL},
+ {{0xac000002, 0xffffffff}, "break", NULL},
+ {{0xac000003, 0xffffffff}, "scall", NULL},
+ {{0xc3e00000, 0xffffffff}, "bret", NULL},
+ {{0xc3c00000, 0xffffffff}, "eret", NULL},
+ {{0xc3a00000, 0xffffffff}, "ret", NULL},
+ {{0xa4000000, 0xfc1f07ff}, "not", "%2, %0"},
+ {{0xb8000000, 0xfc1f07ff}, "mv", "%2, %0"},
+ {{0x71e00000, 0xffe00000}, "mvhi", "%1, %u"},
+ {{0x34000000, 0xffe00000}, "mvi", "%1, %s"},
+
+#define _O(op) {op << 26, 0x3f << 26}
+ /* regular opcodes */
+ {_O(LM32_OP_ADD), "add", "%2, %0, %1" },
+ {_O(LM32_OP_ADDI), "addi", "%1, %0, %s" },
+ {_O(LM32_OP_AND), "and", "%2, %0, %1" },
+ {_O(LM32_OP_ANDHI), "andhi", "%1, %0, %u" },
+ {_O(LM32_OP_ANDI), "andi", "%1, %0, %u" },
+ {_O(LM32_OP_B), "b", "%0", },
+ {_O(LM32_OP_BE), "be", "%1, %0, %r" },
+ {_O(LM32_OP_BG), "bg", "%1, %0, %r" },
+ {_O(LM32_OP_BGE), "bge", "%1, %0, %r" },
+ {_O(LM32_OP_BGEU), "bgeu", "%1, %0, %r" },
+ {_O(LM32_OP_BGU), "bgu", "%1, %0, %r" },
+ {_O(LM32_OP_BI), "bi", "%R", },
+ {_O(LM32_OP_BNE), "bne", "%1, %0, %r" },
+ {_O(LM32_OP_CALL), "call", "%0", },
+ {_O(LM32_OP_CALLI), "calli", "%R", },
+ {_O(LM32_OP_CMPE), "cmpe", "%2, %0, %1" },
+ {_O(LM32_OP_CMPEI), "cmpei", "%1, %0, %s" },
+ {_O(LM32_OP_CMPG), "cmpg", "%2, %0, %1" },
+ {_O(LM32_OP_CMPGE), "cmpge", "%2, %0, %1" },
+ {_O(LM32_OP_CMPGEI), "cmpgei", "%1, %0, %s" },
+ {_O(LM32_OP_CMPGEU), "cmpgeu", "%2, %0, %1" },
+ {_O(LM32_OP_CMPGEUI), "cmpgeui", "%1, %0, %s" },
+ {_O(LM32_OP_CMPGI), "cmpgi", "%1, %0, %s" },
+ {_O(LM32_OP_CMPGU), "cmpgu", "%2, %0, %1" },
+ {_O(LM32_OP_CMPGUI), "cmpgui", "%1, %0, %s" },
+ {_O(LM32_OP_CMPNE), "cmpne", "%2, %0, %1" },
+ {_O(LM32_OP_CMPNEI), "cmpnei", "%1, %0, %s" },
+ {_O(LM32_OP_DIVU), "divu", "%2, %0, %1" },
+ {_O(LM32_OP_LB), "lb", "%1, (%0+%s)" },
+ {_O(LM32_OP_LBU), "lbu", "%1, (%0+%s)" },
+ {_O(LM32_OP_LH), "lh", "%1, (%0+%s)" },
+ {_O(LM32_OP_LHU), "lhu", "%1, (%0+%s)" },
+ {_O(LM32_OP_LW), "lw", "%1, (%0+%s)" },
+ {_O(LM32_OP_MODU), "modu", "%2, %0, %1" },
+ {_O(LM32_OP_MULI), "muli", "%1, %0, %s" },
+ {_O(LM32_OP_MUL), "mul", "%2, %0, %1" },
+ {_O(LM32_OP_NORI), "nori", "%1, %0, %u" },
+ {_O(LM32_OP_NOR), "nor", "%2, %0, %1" },
+ {_O(LM32_OP_ORHI), "orhi", "%1, %0, %u" },
+ {_O(LM32_OP_ORI), "ori", "%1, %0, %u" },
+ {_O(LM32_OP_OR), "or", "%2, %0, %1" },
+ {_O(LM32_OP_RCSR), "rcsr", "%2, %c", },
+ {_O(LM32_OP_SB), "sb", "(%0+%s), %1" },
+ {_O(LM32_OP_SEXTB), "sextb", "%2, %0", },
+ {_O(LM32_OP_SEXTH), "sexth", "%2, %0", },
+ {_O(LM32_OP_SH), "sh", "(%0+%s), %1" },
+ {_O(LM32_OP_SLI), "sli", "%1, %0, %h" },
+ {_O(LM32_OP_SL), "sl", "%2, %0, %1" },
+ {_O(LM32_OP_SRI), "sri", "%1, %0, %h" },
+ {_O(LM32_OP_SR), "sr", "%2, %0, %1" },
+ {_O(LM32_OP_SRUI), "srui", "%1, %0, %d" },
+ {_O(LM32_OP_SRU), "sru", "%2, %0, %s" },
+ {_O(LM32_OP_SUB), "sub", "%2, %0, %s" },
+ {_O(LM32_OP_SW), "sw", "(%0+%s), %1" },
+ {_O(LM32_OP_WCSR), "wcsr", "%c, %1", },
+ {_O(LM32_OP_XNORI), "xnori", "%1, %0, %u" },
+ {_O(LM32_OP_XNOR), "xnor", "%2, %0, %1" },
+ {_O(LM32_OP_XORI), "xori", "%1, %0, %u" },
+ {_O(LM32_OP_XOR), "xor", "%2, %0, %1" },
+#undef _O
+};
+
+static const Lm32OpcodeInfo *find_opcode_info(uint32_t opcode)
+{
+ const Lm32OpcodeInfo *info;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(lm32_opcode_info); i++) {
+ info = &lm32_opcode_info[i];
+ if ((opcode & info->op.mask) == info->op.code) {
+ return info;
+ }
+ }
+
+ return NULL;
+}
+
+int print_insn_lm32(bfd_vma memaddr, struct disassemble_info *info)
+{
+ fprintf_function fprintf_fn = info->fprintf_func;
+ void *stream = info->stream;
+ int rc;
+ uint8_t insn[4];
+ const Lm32OpcodeInfo *opc_info;
+ uint32_t op;
+ const char *args_fmt;
+
+ rc = info->read_memory_func(memaddr, insn, 4, info);
+ if (rc != 0) {
+ info->memory_error_func(rc, memaddr, info);
+ return -1;
+ }
+
+ fprintf_fn(stream, "%02x %02x %02x %02x ",
+ insn[0], insn[1], insn[2], insn[3]);
+
+ op = bfd_getb32(insn);
+ opc_info = find_opcode_info(op);
+ if (opc_info) {
+ fprintf_fn(stream, "%-8s ", opc_info->name);
+ args_fmt = opc_info->args_fmt;
+ while (args_fmt && *args_fmt) {
+ if (*args_fmt == '%') {
+ switch (*(++args_fmt)) {
+ case '0': {
+ uint8_t r0;
+ const char *r0_name;
+ r0 = (op >> 21) & 0x1f;
+ r0_name = find_reg_info(r0)->name;
+ fprintf_fn(stream, "%s", r0_name);
+ break;
+ }
+ case '1': {
+ uint8_t r1;
+ const char *r1_name;
+ r1 = (op >> 16) & 0x1f;
+ r1_name = find_reg_info(r1)->name;
+ fprintf_fn(stream, "%s", r1_name);
+ break;
+ }
+ case '2': {
+ uint8_t r2;
+ const char *r2_name;
+ r2 = (op >> 11) & 0x1f;
+ r2_name = find_reg_info(r2)->name;
+ fprintf_fn(stream, "%s", r2_name);
+ break;
+ }
+ case 'c': {
+ uint8_t csr;
+ const char *csr_name;
+ csr = (op >> 21) & 0x1f;
+ csr_name = find_csr_info(csr)->name;
+ if (csr_name) {
+ fprintf_fn(stream, "%s", csr_name);
+ } else {
+ fprintf_fn(stream, "0x%x", csr);
+ }
+ break;
+ }
+ case 'u': {
+ uint16_t u16;
+ u16 = op & 0xffff;
+ fprintf_fn(stream, "0x%x", u16);
+ break;
+ }
+ case 's': {
+ int16_t s16;
+ s16 = (int16_t)(op & 0xffff);
+ fprintf_fn(stream, "%d", s16);
+ break;
+ }
+ case 'r': {
+ uint32_t rela;
+ rela = memaddr + (((int16_t)(op & 0xffff)) << 2);
+ fprintf_fn(stream, "%x", rela);
+ break;
+ }
+ case 'R': {
+ uint32_t rela;
+ int32_t imm26;
+ imm26 = (int32_t)((op & 0x3ffffff) << 6) >> 4;
+ rela = memaddr + imm26;
+ fprintf_fn(stream, "%x", rela);
+ break;
+ }
+ case 'h': {
+ uint8_t u5;
+ u5 = (op & 0x1f);
+ fprintf_fn(stream, "%d", u5);
+ break;
+ }
+ default:
+ break;
+ }
+ } else {
+ fprintf_fn(stream, "%c", *args_fmt);
+ }
+ args_fmt++;
+ }
+ } else {
+ fprintf_fn(stream, ".word 0x%x", op);
+ }
+
+ return 4;
+}
commit 060544d30f4cc94bced1186e1b042960aebcdfea
Author: Michael Walle <michael at walle.cc>
Date: Sat Mar 31 19:54:09 2012 +0200
milkymist-sysctl: support for new core version
The new version introduces the following new registers:
- SoC clock frequency: read-only of system clock used on the SoC
- debug scratchpad: 8 bit scratchpad register
- debug write lock: write once register, without any function on QEMU
Signed-off-by: Michael Walle <michael at walle.cc>
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index a88548e..8878d2b 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -1,7 +1,7 @@
/*
* QEMU model of the Milkymist System Controller.
*
- * Copyright (c) 2010 Michael Walle <michael at walle.cc>
+ * Copyright (c) 2010-2012 Michael Walle <michael at walle.cc>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -39,20 +39,19 @@ enum {
};
enum {
- R_GPIO_IN = 0,
+ R_GPIO_IN = 0,
R_GPIO_OUT,
R_GPIO_INTEN,
- R_RESERVED0,
- R_TIMER0_CONTROL,
+ R_TIMER0_CONTROL = 4,
R_TIMER0_COMPARE,
R_TIMER0_COUNTER,
- R_RESERVED1,
- R_TIMER1_CONTROL,
+ R_TIMER1_CONTROL = 8,
R_TIMER1_COMPARE,
R_TIMER1_COUNTER,
- R_RESERVED2,
- R_RESERVED3,
- R_ICAP,
+ R_ICAP = 16,
+ R_DBG_SCRATCHPAD = 20,
+ R_DBG_WRITE_LOCK,
+ R_CLK_FREQUENCY = 29,
R_CAPABILITIES,
R_SYSTEM_ID,
R_MAX
@@ -116,6 +115,9 @@ static uint64_t sysctl_read(void *opaque, target_phys_addr_t addr,
case R_TIMER1_CONTROL:
case R_TIMER1_COMPARE:
case R_ICAP:
+ case R_DBG_SCRATCHPAD:
+ case R_DBG_WRITE_LOCK:
+ case R_CLK_FREQUENCY:
case R_CAPABILITIES:
case R_SYSTEM_ID:
r = s->regs[addr];
@@ -145,6 +147,7 @@ static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value,
case R_GPIO_INTEN:
case R_TIMER0_COUNTER:
case R_TIMER1_COUNTER:
+ case R_DBG_SCRATCHPAD:
s->regs[addr] = value;
break;
case R_TIMER0_COMPARE:
@@ -182,11 +185,15 @@ static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value,
case R_ICAP:
sysctl_icap_write(s, value);
break;
+ case R_DBG_WRITE_LOCK:
+ s->regs[addr] = 1;
+ break;
case R_SYSTEM_ID:
qemu_system_reset_request();
break;
case R_GPIO_IN:
+ case R_CLK_FREQUENCY:
case R_CAPABILITIES:
error_report("milkymist_sysctl: write to read-only register 0x"
TARGET_FMT_plx, addr << 2);
@@ -253,6 +260,7 @@ static void milkymist_sysctl_reset(DeviceState *d)
/* defaults */
s->regs[R_ICAP] = ICAP_READY;
s->regs[R_SYSTEM_ID] = s->systemid;
+ s->regs[R_CLK_FREQUENCY] = s->freq_hz;
s->regs[R_CAPABILITIES] = s->capabilities;
s->regs[R_GPIO_IN] = s->strappings;
}
commit de89fd2b885358e649dc38e293d18eecdb78e1ab
Author: Michael Walle <michael at walle.cc>
Date: Sat Mar 31 19:54:05 2012 +0200
target-lm32: init tcg only if available
Once qtest support for target-lm32 arrives, tcg may be disabled.
Signed-off-by: Michael Walle <michael at walle.cc>
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 5db8f8d..78076e4 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -215,7 +215,7 @@ CPULM32State *cpu_lm32_init(const char *cpu_model)
cpu_state_reset(env);
qemu_init_vcpu(env);
- if (!tcg_initialized) {
+ if (tcg_enabled() && !tcg_initialized) {
tcg_initialized = 1;
lm32_translate_init();
}
commit 927b241d66c17501013ccea9f1b56a3d9c7ebb79
Author: Michael Walle <michael at walle.cc>
Date: Sat Mar 31 19:53:51 2012 +0200
tests: fix out-of-tree building for lm32 target
Signed-off-by: Michael Walle <michael at walle.cc>
diff --git a/configure b/configure
index b51a749..4ef5ec6 100755
--- a/configure
+++ b/configure
@@ -3876,7 +3876,8 @@ echo "QEMU_INCLUDES+=$includes" >> $config_target_mak
done # for target in $targets
# build tree in object directory in case the source is not in the current directory
-DIRS="tests tests/tcg tests/tcg/cris slirp audio block net pc-bios/optionrom"
+DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32"
+DIRS="$DIRS slirp audio block net pc-bios/optionrom"
DIRS="$DIRS pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui usb"
@@ -3884,6 +3885,7 @@ DIRS="$DIRS qapi qapi-generated"
DIRS="$DIRS qga trace qom"
FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
+FILES="$FILES tests/tcg/lm32/Makefile"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
FILES="$FILES pc-bios/spapr-rtas/Makefile"
FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
diff --git a/tests/tcg/lm32/Makefile b/tests/tcg/lm32/Makefile
index 03a1abb..9a00ef7 100644
--- a/tests/tcg/lm32/Makefile
+++ b/tests/tcg/lm32/Makefile
@@ -1,4 +1,4 @@
--include ../../config-host.mak
+-include ../../../config-host.mak
CROSS=lm32-elf-
@@ -12,7 +12,10 @@ SIZE = $(CROSS)size
LD = $(CC)
OBJCOPY = $(CROSS)objcopy
-LDFLAGS = -Tlinker.ld
+TSRC_PATH = $(SRC_PATH)/tests/tcg/lm32
+
+LDFLAGS = -T$(TSRC_PATH)/linker.ld
+ASFLAGS += -Wa,-I,$(TSRC_PATH)/
CRT = crt.o
TESTCASES += test_add.tst
@@ -82,13 +85,13 @@ TESTCASES += test_xori.tst
all: build
-%.o: $(SRC_PATH)/tests/lm32/%.c
+%.o: $(TSRC_PATH)/%.c
$(CC) $(CFLAGS) -c $< -o $@
-%.o: $(SRC_PATH)/tests/lm32/%.S
+%.o: $(TSRC_PATH)/%.S
$(AS) $(ASFLAGS) -c $< -o $@
-%.tst: %.o macros.inc $(CRT)
+%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT)
$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
build: $(CRT) $(TESTCASES)
commit b7c8e15a146a7b20021b524f41d6b8072ee093b5
Merge: 4dec465... b0f2663...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Mar 31 12:10:07 2012 +0000
Merge branch 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
* 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm:
pl031: switch clock base to rtc_clock
pl031: rearm alarm timer upon load
arm: switch real-time clocks to rtc_clock
omap: switch omap_lpg to vm_clock
rtc: add -rtc clock=rt
commit 4dec4654604e7e52964ff0201c46d85d179ed35f
Merge: e7c5601... 8df9082...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Mar 31 12:09:06 2012 +0000
Merge branch 'qom-cpu-unicore32.v3' of git://github.com/afaerber/qemu-cpu
* 'qom-cpu-unicore32.v3' of git://github.com/afaerber/qemu-cpu:
target-unicore32: Move CPU-dependent init into initfn
target-unicore32: QOM'ify CPU
target-unicore32: License future contributions under GPLv2+
target-unicore32: Relicense to GPLv2+
MAINTAINERS: Add entry for UniCore32
commit e7c56016f998f9a55012c71e0168c406b50589e6
Merge: 94dd53c... 06ed5d6...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Mar 31 12:06:10 2012 +0000
Merge branch 'target-arm.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
* 'target-arm.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm:
ARM: Permit any ARMv6K CPU to read the MVFR0 and MVFR1 VFP registers.
target-arm: Minimalistic CPU QOM'ification
target-arm: Drop cpu_arm_close()
commit 94dd53c5b6c7b6cfc496a9a49cb73630ce0d6dd1
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 29 10:55:18 2012 +0200
buildfix: check for old pod2man versions
Older pod2man don't have a --utf8 switch, check for this in conffigure
and use it only when present. Fixes build on RHEL-5.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile b/Makefile
index d8e1f36..35c7a2a 100644
--- a/Makefile
+++ b/Makefile
@@ -348,7 +348,6 @@ QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
-POD2MAN = pod2man --utf8
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
diff --git a/configure b/configure
index dd01911..b51a749 100755
--- a/configure
+++ b/configure
@@ -2821,6 +2821,13 @@ if test "$solaris" = "no" ; then
fi
fi
+# test if pod2man has --utf8 option
+if pod2man --help | grep -q utf8; then
+ POD2MAN="pod2man --utf8"
+else
+ POD2MAN="pod2man"
+fi
+
# Use ASLR, no-SEH and DEP if available
if test "$mingw32" = "yes" ; then
for flag in --dynamicbase --no-seh --nxcompat; do
@@ -3358,6 +3365,7 @@ echo "LIBS+=$LIBS" >> $config_host_mak
echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
echo "EXESUF=$EXESUF" >> $config_host_mak
echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
+echo "POD2MAN=$POD2MAN" >> $config_host_mak
# generate list of library paths for linker script
commit bb55b712e8dc4d4eb515144d5c26798fea178cba
Author: Stefan Weil <sw at weilnetz.de>
Date: Tue Mar 27 19:23:53 2012 +0200
Fix conversion from lower to upper case with Turkish locale
Some locale settings let make fail or create wrong results
because tr '[:lower:]' '[:upper:]' which is used to convert
from lower to upper case depends on the locale.
With locale tr_TR.UTF-8, lower case 'i' is not converted to 'I'.
This results in wrong entries in config-host.h like these ones:
#define CONFIG_QEMU_PREFiX "/usr/local"
#define CONFIG_QEMU_BiNDiR "/usr/local/bin"
This problem was reported by Emre Ersin.
The same problem occurs when configure creates the target specific
files config-target.mak. They get wrong declarations:
TARGET_CRiS=y
TARGET_i386=y
TARGET_MiCROBLAZE=y
TARGET_MiPS64=y
TARGET_MiPS=y
TARGET_UNiCORE32=y
It is sufficient to restrict the conversion to the characters a-z.
Using this explicit range avoids the dependency on the locale
settings and is also shorter.
v2:
POSIX says that 'tr a-z' is unspecified outside of the POSIX
locale, so we must set LC_ALL=C to make sure that we are using
POSIX (hint from Eric Blake, thanks).
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/configure b/configure
index 14ef738..dd01911 100755
--- a/configure
+++ b/configure
@@ -3052,12 +3052,12 @@ if test "$cap_ng" = "yes" ; then
echo "CONFIG_LIBCAP=y" >> $config_host_mak
fi
for card in $audio_card_list; do
- def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
+ def=CONFIG_`echo $card | LC_ALL=C tr '[a-z]' '[A-Z]'`
echo "$def=y" >> $config_host_mak
done
echo "CONFIG_AUDIO_DRIVERS=$audio_drv_list" >> $config_host_mak
for drv in $audio_drv_list; do
- def=CONFIG_`echo $drv | tr '[:lower:]' '[:upper:]'`
+ def=CONFIG_`echo $drv | LC_ALL=C tr '[a-z]' '[A-Z]'`
echo "$def=y" >> $config_host_mak
if test "$drv" = "fmod"; then
echo "FMOD_CFLAGS=-I$fmod_inc" >> $config_host_mak
@@ -3618,7 +3618,7 @@ echo "TARGET_INT_ALIGNMENT=$target_int_alignment" >> $config_target_mak
echo "TARGET_LONG_ALIGNMENT=$target_long_alignment" >> $config_target_mak
echo "TARGET_LLONG_ALIGNMENT=$target_llong_alignment" >> $config_target_mak
echo "TARGET_ARCH=$TARGET_ARCH" >> $config_target_mak
-target_arch_name="`echo $TARGET_ARCH | tr '[:lower:]' '[:upper:]'`"
+target_arch_name="`echo $TARGET_ARCH | LC_ALL=C tr '[a-z]' '[A-Z]'`"
echo "TARGET_$target_arch_name=y" >> $config_target_mak
echo "TARGET_ARCH2=$target_arch2" >> $config_target_mak
# TARGET_BASE_ARCH needs to be defined after TARGET_ARCH
diff --git a/scripts/create_config b/scripts/create_config
index 0098e68..470e05e 100755
--- a/scripts/create_config
+++ b/scripts/create_config
@@ -16,7 +16,7 @@ case $line in
prefix=* | [a-z]*dir=*) # directory configuration
name=${line%=*}
value=${line#*=}
- define_name=`echo $name | tr '[:lower:]' '[:upper:]'`
+ define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
eval "define_value=\"$value\""
echo "#define CONFIG_QEMU_$define_name \"$define_value\""
# save for the next definitions
@@ -48,7 +48,7 @@ case $line in
;;
ARCH=*) # configuration
arch=${line#*=}
- arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'`
+ arch_name=`echo $arch | LC_ALL=C tr '[a-z]' '[A-Z]'`
echo "#define HOST_$arch_name 1"
;;
HOST_USB=*)
@@ -73,7 +73,7 @@ case $line in
TARGET_BASE_ARCH=*) # configuration
target_base_arch=${line#*=}
if [ "$target_base_arch" != "$target_arch" ]; then
- base_arch_name=`echo $target_base_arch | tr '[:lower:]' '[:upper:]'`
+ base_arch_name=`echo $target_base_arch | LC_ALL=C tr '[a-z]' '[A-Z]'`
echo "#define TARGET_$base_arch_name 1"
fi
;;
diff --git a/scripts/tracetool b/scripts/tracetool
index 65bd0a1..d675dab 100755
--- a/scripts/tracetool
+++ b/scripts/tracetool
@@ -410,7 +410,7 @@ linetoh_dtrace()
args=$(get_args "$1")
argnames=$(get_argnames "$1", ",")
- nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
+ nameupper=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
# Define an empty function for the trace event
cat <<EOF
@@ -539,7 +539,7 @@ convert()
fi
if [ "$1" = "h" ]; then
name=$(get_name "$str")
- NAME=$(echo $name | tr '[:lower:]' '[:upper:]')
+ NAME=$(echo $name | LC_ALL=C tr '[a-z]' '[A-Z]')
echo "#define TRACE_${NAME}_ENABLED ${enabled}"
fi
done
commit 02b3efcb7509841871038d89406225d1aaf41684
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Fri Mar 30 17:42:27 2012 +0000
qtest: avoid a warning with RTC test
Avoid this warning on OpenBSD:
CC tests/rtc-test.o
/src/qemu/tests/rtc-test.c: In function 'check_time':
/src/qemu/tests/rtc-test.c:171: warning: format '%ld' expects type 'long int', but argument 2 has type 'time_t'
/src/qemu/tests/rtc-test.c:173: warning: format '%ld' expects type 'long int', but argument 2 has type 'time_t'
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index c32b36a..983a980 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -161,12 +161,12 @@ static void check_time(int wiggle)
}
if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
- time_t t, s;
+ long t, s;
start.tm_isdst = datep->tm_isdst;
- t = mktime(datep);
- s = mktime(&start);
+ t = (long)mktime(datep);
+ s = (long)mktime(&start);
if (t < s) {
g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
} else {
commit 6b7cff76e0545b831542bbbdcf3fa2e4f260fbfe
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Fri Mar 30 12:53:54 2012 -0500
qtest: fix 32-bit build
time_t appears to be an unsigned long so use %ld.
Reported-by: Stefan Weil <weil at mail.berlios.de>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qtest.c b/qtest.c
index 53e2b79..cd7186c 100644
--- a/qtest.c
+++ b/qtest.c
@@ -34,7 +34,7 @@ static int irq_levels[MAX_IRQ];
static struct timeval start_time;
static bool qtest_opened;
-#define FMT_timeval "%" PRId64 ".%06" PRId64
+#define FMT_timeval "%ld.%06ld"
/**
* QTest Protocol
commit 86073017e384b65a4b568da25e5873fd2e5e4db5
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Fri Mar 30 19:29:08 2012 +0200
slirp: Signal free input buffer space to io-thread
This massively accelerates slirp reception speed: If data arrives
faster than the guest can read it from the input buffer, the file
descriptor for the corresponding socket was taken out of the fdset for
select. However, the event of the guest reading enough data from the
buffer was not signaled. Thus, the io-thread only noticed this change
on the next time-driven poll. Fix this by kicking the io-thread as
required.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/slirp/sbuf.c b/slirp/sbuf.c
index 5a1ccbf..637f8fe 100644
--- a/slirp/sbuf.c
+++ b/slirp/sbuf.c
@@ -6,6 +6,7 @@
*/
#include <slirp.h>
+#include <main-loop.h>
static void sbappendsb(struct sbuf *sb, struct mbuf *m);
@@ -18,6 +19,8 @@ sbfree(struct sbuf *sb)
void
sbdrop(struct sbuf *sb, int num)
{
+ int limit = sb->sb_datalen / 2;
+
/*
* We can only drop how much we have
* This should never succeed
@@ -29,6 +32,9 @@ sbdrop(struct sbuf *sb, int num)
if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
sb->sb_rptr -= sb->sb_datalen;
+ if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
+ qemu_notify_event();
+ }
}
void
commit d2a16f74f22b4a8d5f8a66d568e729a943136872
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Fri Mar 30 17:39:33 2012 +0000
qtest: fix out of tree build
Trace objects are also needed if tracing is enabled.
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/Makefile b/tests/Makefile
index 29c1e51..a98a848 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -63,6 +63,8 @@ tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qap
tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
+tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
+
# QTest rules
TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
commit d1aaf543a73c33025cf1fcd30b363aadd150cac3
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Mar 28 15:42:07 2012 +0200
qtest: add rtc-test test-case
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/tests/Makefile b/tests/Makefile
index c6fb587..29c1e51 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -16,6 +16,11 @@ check-unit-y += tests/test-coroutine$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
+# All QTests for now are POSIX-only, but the dependencies are
+# really in libqtest, not in the testcases themselves.
+check-qtest-i386-y = tests/rtc-test
+check-qtest-x86_64-y = $(check-qtest-i386-y)
+
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
new file mode 100644
index 0000000..c32b36a
--- /dev/null
+++ b/tests/rtc-test.c
@@ -0,0 +1,263 @@
+/*
+ * QTest testcase for the MC146818 real-time clock
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "libqtest.h"
+#include "hw/mc146818rtc_regs.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static uint8_t base = 0x70;
+
+static int bcd2dec(int value)
+{
+ return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
+}
+
+static int dec2bcd(int value)
+{
+ return ((value / 10) << 4) | (value % 10);
+}
+
+static uint8_t cmos_read(uint8_t reg)
+{
+ outb(base + 0, reg);
+ return inb(base + 1);
+}
+
+static void cmos_write(uint8_t reg, uint8_t val)
+{
+ outb(base + 0, reg);
+ outb(base + 1, val);
+}
+
+static int tm_cmp(struct tm *lhs, struct tm *rhs)
+{
+ time_t a, b;
+ struct tm d1, d2;
+
+ memcpy(&d1, lhs, sizeof(d1));
+ memcpy(&d2, rhs, sizeof(d2));
+
+ a = mktime(&d1);
+ b = mktime(&d2);
+
+ if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ }
+
+ return 0;
+}
+
+#if 0
+static void print_tm(struct tm *tm)
+{
+ printf("%04d-%02d-%02d %02d:%02d:%02d\n",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
+}
+#endif
+
+static void cmos_get_date_time(struct tm *date)
+{
+ int base_year = 2000, hour_offset;
+ int sec, min, hour, mday, mon, year;
+ time_t ts;
+ struct tm dummy;
+
+ sec = cmos_read(RTC_SECONDS);
+ min = cmos_read(RTC_MINUTES);
+ hour = cmos_read(RTC_HOURS);
+ mday = cmos_read(RTC_DAY_OF_MONTH);
+ mon = cmos_read(RTC_MONTH);
+ year = cmos_read(RTC_YEAR);
+
+ if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
+ sec = bcd2dec(sec);
+ min = bcd2dec(min);
+ hour = bcd2dec(hour);
+ mday = bcd2dec(mday);
+ mon = bcd2dec(mon);
+ year = bcd2dec(year);
+ hour_offset = 80;
+ } else {
+ hour_offset = 0x80;
+ }
+
+ if ((cmos_read(0x0B) & REG_B_24H) == 0) {
+ if (hour >= hour_offset) {
+ hour -= hour_offset;
+ hour += 12;
+ }
+ }
+
+ ts = time(NULL);
+ localtime_r(&ts, &dummy);
+
+ date->tm_isdst = dummy.tm_isdst;
+ date->tm_sec = sec;
+ date->tm_min = min;
+ date->tm_hour = hour;
+ date->tm_mday = mday;
+ date->tm_mon = mon - 1;
+ date->tm_year = base_year + year - 1900;
+ date->tm_gmtoff = 0;
+
+ ts = mktime(date);
+}
+
+static void check_time(int wiggle)
+{
+ struct tm start, date[4], end;
+ struct tm *datep;
+ time_t ts;
+
+ /*
+ * This check assumes a few things. First, we cannot guarantee that we get
+ * a consistent reading from the wall clock because we may hit an edge of
+ * the clock while reading. To work around this, we read four clock readings
+ * such that at least two of them should match. We need to assume that one
+ * reading is corrupt so we need four readings to ensure that we have at
+ * least two consecutive identical readings
+ *
+ * It's also possible that we'll cross an edge reading the host clock so
+ * simply check to make sure that the clock reading is within the period of
+ * when we expect it to be.
+ */
+
+ ts = time(NULL);
+ gmtime_r(&ts, &start);
+
+ cmos_get_date_time(&date[0]);
+ cmos_get_date_time(&date[1]);
+ cmos_get_date_time(&date[2]);
+ cmos_get_date_time(&date[3]);
+
+ ts = time(NULL);
+ gmtime_r(&ts, &end);
+
+ if (tm_cmp(&date[0], &date[1]) == 0) {
+ datep = &date[0];
+ } else if (tm_cmp(&date[1], &date[2]) == 0) {
+ datep = &date[1];
+ } else if (tm_cmp(&date[2], &date[3]) == 0) {
+ datep = &date[2];
+ } else {
+ g_assert_not_reached();
+ }
+
+ if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
+ time_t t, s;
+
+ start.tm_isdst = datep->tm_isdst;
+
+ t = mktime(datep);
+ s = mktime(&start);
+ if (t < s) {
+ g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
+ } else {
+ g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
+ }
+
+ g_assert_cmpint(ABS(t - s), <=, wiggle);
+ }
+}
+
+static int wiggle = 2;
+
+static void bcd_check_time(void)
+{
+ /* Set BCD mode */
+ cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
+ check_time(wiggle);
+}
+
+static void dec_check_time(void)
+{
+ /* Set DEC mode */
+ cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM);
+ check_time(wiggle);
+}
+
+static void set_alarm_time(struct tm *tm)
+{
+ int sec;
+
+ sec = tm->tm_sec;
+
+ if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
+ sec = dec2bcd(sec);
+ }
+
+ cmos_write(RTC_SECONDS_ALARM, sec);
+ cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
+ cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
+}
+
+static void alarm_time(void)
+{
+ struct tm now;
+ time_t ts;
+ int i;
+
+ ts = time(NULL);
+ gmtime_r(&ts, &now);
+
+ /* set DEC mode */
+ cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM);
+
+ g_assert(!get_irq(RTC_ISA_IRQ));
+ cmos_read(RTC_REG_C);
+
+ now.tm_sec = (now.tm_sec + 2) % 60;
+ set_alarm_time(&now);
+ cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
+
+ for (i = 0; i < 2 + wiggle; i++) {
+ if (get_irq(RTC_ISA_IRQ)) {
+ break;
+ }
+
+ clock_step(1000000000);
+ }
+
+ g_assert(get_irq(RTC_ISA_IRQ));
+ g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+ g_assert(cmos_read(RTC_REG_C) == 0);
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s = NULL;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ s = qtest_start("-display none -rtc clock=vm");
+ qtest_irq_intercept_in(s, "ioapic");
+
+ qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
+ qtest_add_func("/rtc/dec/check-time", dec_check_time);
+ qtest_add_func("/rtc/alarm-time", alarm_time);
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+
+ return ret;
+}
commit fd94be7ae65195c1fad2b740e0cd4620b25cc5b5
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Mar 28 15:42:06 2012 +0200
rtc: split out macros into a header file and use in test case
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 2b59c36..9c64e0a 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -47,39 +47,6 @@
#define RTC_REINJECT_ON_ACK_COUNT 20
-#define RTC_SECONDS 0
-#define RTC_SECONDS_ALARM 1
-#define RTC_MINUTES 2
-#define RTC_MINUTES_ALARM 3
-#define RTC_HOURS 4
-#define RTC_HOURS_ALARM 5
-#define RTC_ALARM_DONT_CARE 0xC0
-
-#define RTC_DAY_OF_WEEK 6
-#define RTC_DAY_OF_MONTH 7
-#define RTC_MONTH 8
-#define RTC_YEAR 9
-
-#define RTC_REG_A 10
-#define RTC_REG_B 11
-#define RTC_REG_C 12
-#define RTC_REG_D 13
-
-#define REG_A_UIP 0x80
-
-#define REG_B_SET 0x80
-#define REG_B_PIE 0x40
-#define REG_B_AIE 0x20
-#define REG_B_UIE 0x10
-#define REG_B_SQWE 0x08
-#define REG_B_DM 0x04
-#define REG_B_24H 0x02
-
-#define REG_C_UF 0x10
-#define REG_C_IRQF 0x80
-#define REG_C_PF 0x40
-#define REG_C_AF 0x20
-
typedef struct RTCState {
ISADevice dev;
MemoryRegion io;
diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h
index f119930..f286b6a 100644
--- a/hw/mc146818rtc.h
+++ b/hw/mc146818rtc.h
@@ -2,8 +2,7 @@
#define MC146818RTC_H
#include "isa.h"
-
-#define RTC_ISA_IRQ 8
+#include "mc146818rtc_regs.h"
ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq);
void rtc_set_memory(ISADevice *dev, int addr, int val);
diff --git a/hw/mc146818rtc_regs.h b/hw/mc146818rtc_regs.h
new file mode 100644
index 0000000..3ab3770
--- /dev/null
+++ b/hw/mc146818rtc_regs.h
@@ -0,0 +1,62 @@
+/*
+ * QEMU MC146818 RTC emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef RTC_REGS_H
+#define RTC_REGS_H
+
+#define RTC_ISA_IRQ 8
+
+#define RTC_SECONDS 0
+#define RTC_SECONDS_ALARM 1
+#define RTC_MINUTES 2
+#define RTC_MINUTES_ALARM 3
+#define RTC_HOURS 4
+#define RTC_HOURS_ALARM 5
+#define RTC_ALARM_DONT_CARE 0xC0
+
+#define RTC_DAY_OF_WEEK 6
+#define RTC_DAY_OF_MONTH 7
+#define RTC_MONTH 8
+#define RTC_YEAR 9
+
+#define RTC_REG_A 10
+#define RTC_REG_B 11
+#define RTC_REG_C 12
+#define RTC_REG_D 13
+
+#define REG_A_UIP 0x80
+
+#define REG_B_SET 0x80
+#define REG_B_PIE 0x40
+#define REG_B_AIE 0x20
+#define REG_B_UIE 0x10
+#define REG_B_SQWE 0x08
+#define REG_B_DM 0x04
+#define REG_B_24H 0x02
+
+#define REG_C_UF 0x10
+#define REG_C_IRQF 0x80
+#define REG_C_PF 0x40
+#define REG_C_AF 0x20
+
+#endif
commit 49ee35907723a28e91da27537f48c9d8696c427e
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Mar 28 15:42:05 2012 +0200
qtest: add C version of test infrastructure
This also includes a qtest wrapper script to make it easier to launch qtest
tests directly.
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/osdep.h b/osdep.h
index 156666e..428285c 100644
--- a/osdep.h
+++ b/osdep.h
@@ -140,4 +140,6 @@ static inline void qemu_timersub(const struct timeval *val1,
#define qemu_timersub timersub
#endif
+void qemu_set_cloexec(int fd);
+
#endif
diff --git a/qemu-common.h b/qemu-common.h
index c9e96a8..4647dd9 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -190,7 +190,6 @@ ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags)
QEMU_WARN_UNUSED_RESULT;
ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags)
QEMU_WARN_UNUSED_RESULT;
-void qemu_set_cloexec(int fd);
#ifndef _WIN32
int qemu_eventfd(int pipefd[2]);
diff --git a/tests/Makefile b/tests/Makefile
index 17f6ece..c6fb587 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -58,11 +58,22 @@ tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qap
tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
+# QTest rules
+
+TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
+QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
+check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
+
+qtest-obj-y = tests/libqtest.o $(oslib-obj-y)
+$(check-qtest-y): $(qtest-obj-y)
+
.PHONY: check-help
check-help:
@echo "Regression testing targets:"
@echo
@echo " make check Run all tests"
+ @echo " make check-qtest-TARGET Run qtest tests for given target"
+ @echo " make check-qtest Run qtest tests"
@echo " make check-unit Run qobject tests"
@echo " make check-block Run block tests"
@echo " make check-report.html Generates an HTML test report"
@@ -81,18 +92,27 @@ GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
# gtester tests, possibly with verbose output
+.PHONY: $(patsubst %, check-qtest-%, $(QTEST_TARGETS))
+$(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y)
+ $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
+ gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
+
.PHONY: $(patsubst %, check-%, $(check-unit-y))
$(patsubst %, check-%, $(check-unit-y)): check-%: %
$(call quiet-command,gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
# gtester tests with XML output
+$(patsubst %, check-report-qtest-%.xml, $(QTEST_TARGETS)): check-report-qtest-%.xml: $(check-qtest-y)
+ $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
+ gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
+
check-report-unit.xml: $(check-unit-y)
$(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^, "GTESTER $@")
# Reports and overall runs
-check-report.xml: check-report-unit.xml
+check-report.xml: $(patsubst %,check-report-qtest-%.xml, $(QTEST_TARGETS)) check-report-unit.xml
$(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, " GEN $@")
check-report.html: check-report.xml
@@ -107,7 +127,8 @@ check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF)
# Consolidated targets
-.PHONY: check-unit check
+.PHONY: check-qtest check-unit check
+check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
check-unit: $(patsubst %,check-%, $(check-unit-y))
check-block: $(patsubst %,check-%, $(check-block-y))
-check: check-unit
+check: check-unit check-qtest
diff --git a/tests/libqtest.c b/tests/libqtest.c
new file mode 100644
index 0000000..d47969e
--- /dev/null
+++ b/tests/libqtest.c
@@ -0,0 +1,387 @@
+/*
+ * QTest
+ *
+ * Copyright IBM, Corp. 2012
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ * Paolo Bonzini <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "libqtest.h"
+
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "osdep.h"
+
+#define MAX_IRQ 256
+
+QTestState *global_qtest;
+
+struct QTestState
+{
+ int fd;
+ bool irq_level[MAX_IRQ];
+ GString *rx;
+ gchar *pid_file;
+};
+
+#define g_assert_no_errno(ret) do { \
+ g_assert_cmpint(ret, !=, -1); \
+} while (0)
+
+QTestState *qtest_init(const char *extra_args)
+{
+ QTestState *s;
+ struct sockaddr_un addr;
+ int sock, ret, i;
+ gchar *socket_path;
+ gchar *pid_file;
+ gchar *command;
+ const char *qemu_binary;
+ pid_t pid;
+ socklen_t addrlen;
+
+ qemu_binary = getenv("QTEST_QEMU_BINARY");
+ g_assert(qemu_binary != NULL);
+
+ socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
+ pid_file = g_strdup_printf("/tmp/qtest-%d.pid", getpid());
+
+ s = g_malloc(sizeof(*s));
+
+ sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ g_assert_no_errno(sock);
+
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
+ qemu_set_cloexec(sock);
+
+ do {
+ ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+ } while (ret == -1 && errno == EINTR);
+ g_assert_no_errno(ret);
+ listen(sock, 1);
+
+ pid = fork();
+ if (pid == 0) {
+ command = g_strdup_printf("%s "
+ "-qtest unix:%s,nowait "
+ "-qtest-log /dev/null "
+ "-pidfile %s "
+ "-machine accel=qtest "
+ "%s", qemu_binary, socket_path,
+ pid_file,
+ extra_args ?: "");
+
+ ret = system(command);
+ exit(ret);
+ g_free(command);
+ }
+
+ do {
+ ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
+ } while (ret == -1 && errno == EINTR);
+ g_assert_no_errno(ret);
+ close(sock);
+
+ s->fd = ret;
+ s->rx = g_string_new("");
+ s->pid_file = pid_file;
+ for (i = 0; i < MAX_IRQ; i++) {
+ s->irq_level[i] = false;
+ }
+
+ g_free(socket_path);
+
+ return s;
+}
+
+void qtest_quit(QTestState *s)
+{
+ FILE *f;
+ char buffer[1024];
+
+ f = fopen(s->pid_file, "r");
+ if (f) {
+ if (fgets(buffer, sizeof(buffer), f)) {
+ pid_t pid = atoi(buffer);
+ int status = 0;
+
+ kill(pid, SIGTERM);
+ waitpid(pid, &status, 0);
+ }
+
+ fclose(f);
+ }
+}
+
+static void qtest_sendf(QTestState *s, const char *fmt, ...)
+{
+ va_list ap;
+ gchar *str;
+ size_t size, offset;
+
+ va_start(ap, fmt);
+ str = g_strdup_vprintf(fmt, ap);
+ va_end(ap);
+ size = strlen(str);
+
+ offset = 0;
+ while (offset < size) {
+ ssize_t len;
+
+ len = write(s->fd, str + offset, size - offset);
+ if (len == -1 && errno == EINTR) {
+ continue;
+ }
+
+ g_assert_no_errno(len);
+ g_assert_cmpint(len, >, 0);
+
+ offset += len;
+ }
+}
+
+static GString *qtest_recv_line(QTestState *s)
+{
+ GString *line;
+ size_t offset;
+ char *eol;
+
+ while ((eol = strchr(s->rx->str, '\n')) == NULL) {
+ ssize_t len;
+ char buffer[1024];
+
+ len = read(s->fd, buffer, sizeof(buffer));
+ if (len == -1 && errno == EINTR) {
+ continue;
+ }
+
+ if (len == -1 || len == 0) {
+ fprintf(stderr, "Broken pipe\n");
+ exit(1);
+ }
+
+ g_string_append_len(s->rx, buffer, len);
+ }
+
+ offset = eol - s->rx->str;
+ line = g_string_new_len(s->rx->str, offset);
+ g_string_erase(s->rx, 0, offset + 1);
+
+ return line;
+}
+
+static gchar **qtest_rsp(QTestState *s, int expected_args)
+{
+ GString *line;
+ gchar **words;
+ int i;
+
+redo:
+ line = qtest_recv_line(s);
+ words = g_strsplit(line->str, " ", 0);
+ g_string_free(line, TRUE);
+
+ if (strcmp(words[0], "IRQ") == 0) {
+ int irq;
+
+ g_assert(words[1] != NULL);
+ g_assert(words[2] != NULL);
+
+ irq = strtoul(words[2], NULL, 0);
+ g_assert_cmpint(irq, >=, 0);
+ g_assert_cmpint(irq, <, MAX_IRQ);
+
+ if (strcmp(words[1], "raise") == 0) {
+ s->irq_level[irq] = true;
+ } else {
+ s->irq_level[irq] = false;
+ }
+
+ g_strfreev(words);
+ goto redo;
+ }
+
+ g_assert(words[0] != NULL);
+ g_assert_cmpstr(words[0], ==, "OK");
+
+ if (expected_args) {
+ for (i = 0; i < expected_args; i++) {
+ g_assert(words[i] != NULL);
+ }
+ } else {
+ g_strfreev(words);
+ }
+
+ return words;
+}
+
+const char *qtest_get_arch(void)
+{
+ const char *qemu = getenv("QTEST_QEMU_BINARY");
+ const char *end = strrchr(qemu, '/');
+
+ return end + strlen("/qemu-system-");
+}
+
+bool qtest_get_irq(QTestState *s, int num)
+{
+ /* dummy operation in order to make sure irq is up to date */
+ qtest_inb(s, 0);
+
+ return s->irq_level[num];
+}
+
+static int64_t qtest_clock_rsp(QTestState *s)
+{
+ gchar **words;
+ int64_t clock;
+ words = qtest_rsp(s, 2);
+ clock = g_ascii_strtoll(words[1], NULL, 0);
+ g_strfreev(words);
+ return clock;
+}
+
+int64_t qtest_clock_step_next(QTestState *s)
+{
+ qtest_sendf(s, "clock_step\n");
+ return qtest_clock_rsp(s);
+}
+
+int64_t qtest_clock_step(QTestState *s, int64_t step)
+{
+ qtest_sendf(s, "clock_step %"PRIi64"\n", step);
+ return qtest_clock_rsp(s);
+}
+
+int64_t qtest_clock_set(QTestState *s, int64_t val)
+{
+ qtest_sendf(s, "clock_set %"PRIi64"\n", val);
+ return qtest_clock_rsp(s);
+}
+
+void qtest_irq_intercept_out(QTestState *s, const char *qom_path)
+{
+ qtest_sendf(s, "irq_intercept_out %s\n", qom_path);
+ qtest_rsp(s, 0);
+}
+
+void qtest_irq_intercept_in(QTestState *s, const char *qom_path)
+{
+ qtest_sendf(s, "irq_intercept_in %s\n", qom_path);
+ qtest_rsp(s, 0);
+}
+
+static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
+{
+ qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
+ qtest_rsp(s, 0);
+}
+
+void qtest_outb(QTestState *s, uint16_t addr, uint8_t value)
+{
+ qtest_out(s, "outb", addr, value);
+}
+
+void qtest_outw(QTestState *s, uint16_t addr, uint16_t value)
+{
+ qtest_out(s, "outw", addr, value);
+}
+
+void qtest_outl(QTestState *s, uint16_t addr, uint32_t value)
+{
+ qtest_out(s, "outl", addr, value);
+}
+
+static uint32_t qtest_in(QTestState *s, const char *cmd, uint16_t addr)
+{
+ gchar **args;
+ uint32_t value;
+
+ qtest_sendf(s, "%s 0x%x\n", cmd, addr);
+ args = qtest_rsp(s, 2);
+ value = strtoul(args[1], NULL, 0);
+ g_strfreev(args);
+
+ return value;
+}
+
+uint8_t qtest_inb(QTestState *s, uint16_t addr)
+{
+ return qtest_in(s, "inb", addr);
+}
+
+uint16_t qtest_inw(QTestState *s, uint16_t addr)
+{
+ return qtest_in(s, "inw", addr);
+}
+
+uint32_t qtest_inl(QTestState *s, uint16_t addr)
+{
+ return qtest_in(s, "inl", addr);
+}
+
+static int hex2nib(char ch)
+{
+ if (ch >= '0' && ch <= '9') {
+ return ch - '0';
+ } else if (ch >= 'a' && ch <= 'f') {
+ return 10 + (ch - 'a');
+ } else if (ch >= 'A' && ch <= 'F') {
+ return 10 + (ch - 'a');
+ } else {
+ return -1;
+ }
+}
+
+void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
+{
+ uint8_t *ptr = data;
+ gchar **args;
+ size_t i;
+
+ qtest_sendf(s, "read 0x%x 0x%x\n", addr, size);
+ args = qtest_rsp(s, 2);
+
+ for (i = 0; i < size; i++) {
+ ptr[i] = hex2nib(args[1][2 + (i * 2)]) << 4;
+ ptr[i] |= hex2nib(args[1][2 + (i * 2) + 1]);
+ }
+
+ g_strfreev(args);
+}
+
+void qtest_add_func(const char *str, void (*fn))
+{
+ gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
+ g_test_add_func(path, fn);
+}
+
+void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
+{
+ const uint8_t *ptr = data;
+ size_t i;
+
+ qtest_sendf(s, "write 0x%x 0x%x 0x", addr, size);
+ for (i = 0; i < size; i++) {
+ qtest_sendf(s, "%02x", ptr[i]);
+ }
+ qtest_sendf(s, "\n");
+ qtest_rsp(s, 0);
+}
diff --git a/tests/libqtest.h b/tests/libqtest.h
new file mode 100644
index 0000000..2ca85a9
--- /dev/null
+++ b/tests/libqtest.h
@@ -0,0 +1,335 @@
+/*
+ * QTest
+ *
+ * Copyright IBM, Corp. 2012
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ * Paolo Bonzini <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#ifndef LIBQTEST_H
+#define LIBQTEST_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+typedef struct QTestState QTestState;
+
+extern QTestState *global_qtest;
+
+/**
+ * qtest_init:
+ * @extra_args: other arguments to pass to QEMU.
+ */
+QTestState *qtest_init(const char *extra_args);
+
+/**
+ * qtest_quit:
+ * @s: QTestState instance to operate on.
+ *
+ * Shut down the QEMU process associated to @s.
+ */
+void qtest_quit(QTestState *s);
+
+/**
+ * qtest_get_irq:
+ * @s: QTestState instance to operate on.
+ * @num: Interrupt to observe.
+ *
+ * Return the level of the @num interrupt.
+ */
+bool qtest_get_irq(QTestState *s, int num);
+
+/**
+ * qtest_irq_intercept_in:
+ * @s: QTestState instance to operate on.
+ * @string: QOM path of a device.
+ *
+ * Associate qtest irqs with the GPIO-in pins of the device
+ * whose path is specified by @string.
+ */
+void qtest_irq_intercept_in(QTestState *s, const char *string);
+
+/**
+ * qtest_irq_intercept_out:
+ * @s: QTestState instance to operate on.
+ * @string: QOM path of a device.
+ *
+ * Associate qtest irqs with the GPIO-out pins of the device
+ * whose path is specified by @string.
+ */
+void qtest_irq_intercept_out(QTestState *s, const char *string);
+
+/**
+ * qtest_outb:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write an 8-bit value to an I/O port.
+ */
+void qtest_outb(QTestState *s, uint16_t addr, uint8_t value);
+
+/**
+ * qtest_outw:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 16-bit value to an I/O port.
+ */
+void qtest_outw(QTestState *s, uint16_t addr, uint16_t value);
+
+/**
+ * qtest_outl:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 32-bit value to an I/O port.
+ */
+void qtest_outl(QTestState *s, uint16_t addr, uint32_t value);
+
+/**
+ * qtest_inb:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to read from.
+ * @value: Value being written.
+ *
+ * Returns an 8-bit value from an I/O port.
+ */
+uint8_t qtest_inb(QTestState *s, uint16_t addr);
+
+/**
+ * qtest_inw:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to read from.
+ * @value: Value being written.
+ *
+ * Returns a 16-bit value from an I/O port.
+ */
+uint16_t qtest_inw(QTestState *s, uint16_t addr);
+
+/**
+ * qtest_inl:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to read from.
+ * @value: Value being written.
+ *
+ * Returns a 32-bit value from an I/O port.
+ */
+uint32_t qtest_inl(QTestState *s, uint16_t addr);
+
+/**
+ * qtest_memread:
+ * @s: QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer.
+ */
+void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
+
+/**
+ * qtest_memwrite:
+ * @s: QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory.
+ */
+void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size);
+
+/**
+ * qtest_clock_step_next:
+ * @s: QTestState instance to operate on.
+ *
+ * Advance the vm_clock to the next deadline. Return the current
+ * value of the vm_clock in nanoseconds.
+ */
+int64_t qtest_clock_step_next(QTestState *s);
+
+/**
+ * qtest_clock_step:
+ * @s: QTestState instance to operate on.
+ * @step: Number of nanoseconds to advance the clock by.
+ *
+ * Advance the vm_clock by @step nanoseconds. Return the current
+ * value of the vm_clock in nanoseconds.
+ */
+int64_t qtest_clock_step(QTestState *s, int64_t step);
+
+/**
+ * qtest_clock_set:
+ * @s: QTestState instance to operate on.
+ * @val: Nanoseconds value to advance the clock to.
+ *
+ * Advance the vm_clock to @val nanoseconds since the VM was launched.
+ * Return the current value of the vm_clock in nanoseconds.
+ */
+int64_t qtest_clock_set(QTestState *s, int64_t val);
+
+/**
+ * qtest_get_arch:
+ *
+ * Returns the architecture for the QEMU executable under test.
+ */
+const char *qtest_get_arch(void);
+
+/**
+ * qtest_add_func:
+ * @str: Test case path.
+ * @fn: Test case function
+ *
+ * Add a GTester testcase with the given name and function.
+ * The path is prefixed with the architecture under test, as
+ * returned by qtest_get_arch.
+ */
+void qtest_add_func(const char *str, void (*fn));
+
+/**
+ * qtest_start:
+ * @args: other arguments to pass to QEMU
+ *
+ * Start QEMU and assign the resulting QTestState to a global variable.
+ * The global variable is used by "shortcut" macros documented below.
+ */
+#define qtest_start(args) ( \
+ global_qtest = qtest_init((args)) \
+ )
+
+/**
+ * get_irq:
+ * @num: Interrupt to observe.
+ *
+ * Return the level of the @num interrupt.
+ */
+#define get_irq(num) qtest_get_irq(global_qtest, num)
+
+/**
+ * irq_intercept_in:
+ * @string: QOM path of a device.
+ *
+ * Associate qtest irqs with the GPIO-in pins of the device
+ * whose path is specified by @string.
+ */
+#define irq_intercept_in(string) qtest_irq_intercept_in(global_qtest, string)
+
+/**
+ * qtest_irq_intercept_out:
+ * @string: QOM path of a device.
+ *
+ * Associate qtest irqs with the GPIO-out pins of the device
+ * whose path is specified by @string.
+ */
+#define irq_intercept_out(string) qtest_irq_intercept_out(global_qtest, string)
+
+/**
+ * outb:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write an 8-bit value to an I/O port.
+ */
+#define outb(addr, val) qtest_outb(global_qtest, addr, val)
+
+/**
+ * outw:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 16-bit value to an I/O port.
+ */
+#define outw(addr, val) qtest_outw(global_qtest, addr, val)
+
+/**
+ * outl:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 32-bit value to an I/O port.
+ */
+#define outl(addr, val) qtest_outl(global_qtest, addr, val)
+
+/**
+ * inb:
+ * @addr: I/O port to read from.
+ * @value: Value being written.
+ *
+ * Returns an 8-bit value from an I/O port.
+ */
+#define inb(addr) qtest_inb(global_qtest, addr)
+
+/**
+ * inw:
+ * @addr: I/O port to read from.
+ * @value: Value being written.
+ *
+ * Returns a 16-bit value from an I/O port.
+ */
+#define inw(addr) qtest_inw(global_qtest, addr)
+
+/**
+ * inl:
+ * @addr: I/O port to read from.
+ * @value: Value being written.
+ *
+ * Returns a 32-bit value from an I/O port.
+ */
+#define inl(addr) qtest_inl(global_qtest, addr)
+
+/**
+ * memread:
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer.
+ */
+#define memread(addr, data, size) qtest_memread(global_qtest, addr, data, size)
+
+/**
+ * memwrite:
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory.
+ */
+#define memwrite(addr, data, size) qtest_memwrite(global_qtest, addr, data, size)
+
+/**
+ * clock_step_next:
+ *
+ * Advance the vm_clock to the next deadline. Return the current
+ * value of the vm_clock in nanoseconds.
+ */
+#define clock_step_next() qtest_clock_step_next(global_qtest)
+
+/**
+ * clock_step:
+ * @step: Number of nanoseconds to advance the clock by.
+ *
+ * Advance the vm_clock by @step nanoseconds. Return the current
+ * value of the vm_clock in nanoseconds.
+ */
+#define clock_step(step) qtest_clock_step(global_qtest, step)
+
+/**
+ * clock_set:
+ * @val: Nanoseconds value to advance the clock to.
+ *
+ * Advance the vm_clock to @val nanoseconds since the VM was launched.
+ * Return the current value of the vm_clock in nanoseconds.
+ */
+#define clock_set(val) qtest_clock_set(global_qtest, val)
+
+#endif
commit 8156be561019bd0fc17729e9a528f6c81eea9186
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Mar 28 15:42:04 2012 +0200
qtest: add clock management
This patch combines qtest and -icount together to turn the vm_clock
into a source that can be fully managed by the client. To this end new
commands clock_step and clock_set are added. Hooking them with libqtest
is left as an exercise to the reader.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/cpus.c b/cpus.c
index ab8d67b..eb22bd5 100644
--- a/cpus.c
+++ b/cpus.c
@@ -34,6 +34,7 @@
#include "qemu-thread.h"
#include "cpus.h"
+#include "qtest.h"
#include "main-loop.h"
#ifndef _WIN32
@@ -238,6 +239,20 @@ static void icount_warp_rt(void *opaque)
vm_clock_warp_start = -1;
}
+void qtest_clock_warp(int64_t dest)
+{
+ int64_t clock = qemu_get_clock_ns(vm_clock);
+ assert(qtest_enabled());
+ while (clock < dest) {
+ int64_t deadline = qemu_clock_deadline(vm_clock);
+ int64_t warp = MIN(dest - clock, deadline);
+ qemu_icount_bias += warp;
+ qemu_run_timers(vm_clock);
+ clock = qemu_get_clock_ns(vm_clock);
+ }
+ qemu_notify_event();
+}
+
void qemu_clock_warp(QEMUClock *clock)
{
int64_t deadline;
@@ -264,6 +279,11 @@ void qemu_clock_warp(QEMUClock *clock)
return;
}
+ if (qtest_enabled()) {
+ /* When testing, qtest commands advance icount. */
+ return;
+ }
+
vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
deadline = qemu_clock_deadline(vm_clock);
if (deadline > 0) {
diff --git a/cpus.h b/cpus.h
index 4ea2fe2..81bd817 100644
--- a/cpus.h
+++ b/cpus.h
@@ -11,6 +11,8 @@ void cpu_synchronize_all_states(void);
void cpu_synchronize_all_post_reset(void);
void cpu_synchronize_all_post_init(void);
+void qtest_clock_warp(int64_t dest);
+
/* vl.c */
extern int smp_cores;
extern int smp_threads;
diff --git a/qemu-timer.c b/qemu-timer.c
index d7f56e5..80bcc56 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -397,7 +397,7 @@ int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
}
-static void qemu_run_timers(QEMUClock *clock)
+void qemu_run_timers(QEMUClock *clock)
{
QEMUTimer **ptimer_head, *ts;
int64_t current_time;
diff --git a/qemu-timer.h b/qemu-timer.h
index de17f3b..661bbe7 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -59,6 +59,7 @@ int qemu_timer_pending(QEMUTimer *ts);
int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
+void qemu_run_timers(QEMUClock *clock);
void qemu_run_all_timers(void);
int qemu_alarm_pending(void);
void configure_alarms(char const *opt);
diff --git a/qtest.c b/qtest.c
index a1eca49..53e2b79 100644
--- a/qtest.c
+++ b/qtest.c
@@ -18,6 +18,7 @@
#include "memory.h"
#include "hw/irq.h"
#include "sysemu.h"
+#include "cpus.h"
#define MAX_IRQ 256
@@ -44,6 +45,30 @@ static bool qtest_opened;
*
* Valid requests
*
+ * Clock management:
+ *
+ * The qtest client is completely in charge of the vm_clock. qtest commands
+ * let you adjust the value of the clock (monotonically). All the commands
+ * return the current value of the clock in nanoseconds.
+ *
+ * > clock_step
+ * < OK VALUE
+ *
+ * Advance the clock to the next deadline. Useful when waiting for
+ * asynchronous events.
+ *
+ * > clock_step NS
+ * < OK VALUE
+ *
+ * Advance the clock by NS nanoseconds.
+ *
+ * > clock_set NS
+ * < OK VALUE
+ *
+ * Advance the clock to NS nanoseconds (do nothing if it's already past).
+ *
+ * PIO and memory access:
+ *
* > outb ADDR VALUE
* < OK
*
@@ -299,6 +324,25 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
+ } else if (strcmp(words[0], "clock_step") == 0) {
+ int64_t ns;
+
+ if (words[1]) {
+ ns = strtoll(words[1], NULL, 0);
+ } else {
+ ns = qemu_clock_deadline(vm_clock);
+ }
+ qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns);
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
+ } else if (strcmp(words[0], "clock_set") == 0) {
+ int64_t ns;
+
+ g_assert(words[1]);
+ ns = strtoll(words[1], NULL, 0);
+ qtest_clock_warp(ns);
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
} else {
qtest_send_prefix(chr);
qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
@@ -377,6 +421,7 @@ int qtest_init(void)
g_assert(qtest_chrdev != NULL);
+ configure_icount("0");
chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
commit 2028834574e75de9d34995fbaf09a8b35cb9daa0
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Mar 28 15:42:03 2012 +0200
qtest: IRQ interception infrastructure
Since /i440fx/piix3 is being removed from the composition tree, the
IO-APIC is placed under /i440fx. This is wrong and should be changed
as soon as the /i440fx/piix3 path is put back.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/irq.c b/hw/irq.c
index 62f766e..d413a0b 100644
--- a/hw/irq.c
+++ b/hw/irq.c
@@ -104,3 +104,20 @@ qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
{
return qemu_allocate_irqs(proxy_irq_handler, target, n);
}
+
+void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
+{
+ int i;
+ qemu_irq *old_irqs = qemu_allocate_irqs(NULL, NULL, n);
+ for (i = 0; i < n; i++) {
+ *old_irqs[i] = *gpio_in[i];
+ gpio_in[i]->handler = handler;
+ gpio_in[i]->opaque = old_irqs;
+ }
+}
+
+void qemu_irq_intercept_out(qemu_irq **gpio_out, qemu_irq_handler handler, int n)
+{
+ qemu_irq *old_irqs = *gpio_out;
+ *gpio_out = qemu_allocate_irqs(handler, old_irqs, n);
+}
diff --git a/hw/irq.h b/hw/irq.h
index 64da2fd..56c55f0 100644
--- a/hw/irq.h
+++ b/hw/irq.h
@@ -38,4 +38,9 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
*/
qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
+/* For internal use in qtest. Similar to qemu_irq_split, but operating
+ on an existing vector of qemu_irq. */
+void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n);
+void qemu_irq_intercept_out(qemu_irq **gpio_out, qemu_irq_handler handler, int n);
+
#endif
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 3f99f9a..ec5118f 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -107,6 +107,9 @@ static void ioapic_init(GSIState *gsi_state)
} else {
dev = qdev_create(NULL, "ioapic");
}
+ /* FIXME: this should be under the piix3. */
+ object_property_add_child(object_resolve_path("i440fx", NULL),
+ "ioapic", OBJECT(dev), NULL);
qdev_init_nofail(dev);
d = sysbus_from_qdev(dev);
sysbus_mmio_map(d, 0, 0xfec00000);
diff --git a/qtest.c b/qtest.c
index 46ebda1..a1eca49 100644
--- a/qtest.c
+++ b/qtest.c
@@ -12,6 +12,7 @@
*/
#include "qtest.h"
+#include "hw/qdev.h"
#include "qemu-char.h"
#include "ioport.h"
#include "memory.h"
@@ -24,6 +25,7 @@ const char *qtest_chrdev;
const char *qtest_log;
int qtest_allowed = 0;
+static DeviceState *irq_intercept_dev;
static FILE *qtest_log_fp;
static CharDriverState *qtest_chr;
static GString *inbuf;
@@ -66,18 +68,30 @@ static bool qtest_opened;
* > write ADDR SIZE DATA
* < OK
*
- * Valid async messages:
- *
- * IRQ raise NUM
- * IRQ lower NUM
- *
* ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
*
* DATA is an arbitrarily long hex number prefixed with '0x'. If it's smaller
* than the expected size, the value will be zero filled at the end of the data
* sequence.
*
- * NUM is an IRQ number.
+ * IRQ management:
+ *
+ * > irq_intercept_in QOM-PATH
+ * < OK
+ *
+ * > irq_intercept_out QOM-PATH
+ * < OK
+ *
+ * Attach to the gpio-in (resp. gpio-out) pins exported by the device at
+ * QOM-PATH. When the pin is triggered, one of the following async messages
+ * will be printed to the qtest stream:
+ *
+ * IRQ raise NUM
+ * IRQ lower NUM
+ *
+ * where NUM is an IRQ number. For the PC, interrupts can be intercepted
+ * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
+ * NUM=0 even though it is remapped to GSI 2).
*/
static int hex2nib(char ch)
@@ -133,6 +147,20 @@ static void qtest_send(CharDriverState *chr, const char *fmt, ...)
}
}
+static void qtest_irq_handler(void *opaque, int n, int level)
+{
+ qemu_irq *old_irqs = opaque;
+ qemu_set_irq(old_irqs[n], level);
+
+ if (irq_levels[n] != level) {
+ CharDriverState *chr = qtest_chr;
+ irq_levels[n] = level;
+ qtest_send_prefix(chr);
+ qtest_send(chr, "IRQ %s %d\n",
+ level ? "raise" : "lower", n);
+ }
+}
+
static void qtest_process_command(CharDriverState *chr, gchar **words)
{
const gchar *command;
@@ -155,9 +183,40 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
}
g_assert(command);
- if (strcmp(words[0], "outb") == 0 ||
- strcmp(words[0], "outw") == 0 ||
- strcmp(words[0], "outl") == 0) {
+ if (strcmp(words[0], "irq_intercept_out") == 0
+ || strcmp(words[0], "irq_intercept_in") == 0) {
+ DeviceState *dev;
+
+ g_assert(words[1]);
+ dev = DEVICE(object_resolve_path(words[1], NULL));
+ if (!dev) {
+ qtest_send_prefix(chr);
+ qtest_send(chr, "FAIL Unknown device\n");
+ return;
+ }
+
+ if (irq_intercept_dev) {
+ qtest_send_prefix(chr);
+ if (irq_intercept_dev != dev) {
+ qtest_send(chr, "FAIL IRQ intercept already enabled\n");
+ } else {
+ qtest_send(chr, "OK\n");
+ }
+ return;
+ }
+
+ if (words[0][14] == 'o') {
+ qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out);
+ } else {
+ qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in);
+ }
+ irq_intercept_dev = dev;
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK\n");
+
+ } else if (strcmp(words[0], "outb") == 0 ||
+ strcmp(words[0], "outw") == 0 ||
+ strcmp(words[0], "outl") == 0) {
uint16_t addr;
uint32_t value;
@@ -312,21 +371,6 @@ static void qtest_event(void *opaque, int event)
}
}
-static void qtest_set_irq(void *opaque, int irq, int level)
-{
- CharDriverState *chr = qtest_chr;
- bool changed;
-
- changed = (irq_levels[irq] != level);
- irq_levels[irq] = level;
-
- if (changed) {
- qtest_send_prefix(chr);
- qtest_send(chr, "IRQ %s %d\n",
- level ? "raise" : "lower", irq);
- }
-}
-
int qtest_init(void)
{
CharDriverState *chr;
commit c7f0f3b1c826901358a0656f80a5fabb88f73c61
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Mar 28 15:42:02 2012 +0200
qtest: add test framework
The idea behind qtest is pretty simple. Instead of executing a CPU via TCG or
KVM, rely on an external process to send events to the device model that the CPU
would normally generate.
qtest presents itself as an accelerator. In addition, a new option is added to
establish a qtest server (-qtest) that takes a character device. This is what
allows the external process to send CPU events to the device model.
qtest uses a simple line based protocol to send the events. Documentation of
that protocol is in qtest.c.
I considered reusing the monitor for this job. Adding interrupts would be a bit
difficult. In addition, logging would also be difficult.
qtest has extensive logging support. All protocol commands are logged with
time stamps using a new command line option (-qtest-log). Logging is important
since ultimately, this is a feature for debugging.
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile.objs b/Makefile.objs
index 226b01d..e9842b0 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -322,6 +322,8 @@ hw-obj-$(CONFIG_DP8393X) += dp8393x.o
hw-obj-$(CONFIG_DS1225Y) += ds1225y.o
hw-obj-$(CONFIG_MIPSNET) += mipsnet.o
+hw-obj-y += qtest.o
+
# Sound
sound-obj-y =
sound-obj-$(CONFIG_SB16) += sb16.o
diff --git a/cpu-exec.c b/cpu-exec.c
index 0fa8325..d153f97 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -21,6 +21,7 @@
#include "disas.h"
#include "tcg.h"
#include "qemu-barrier.h"
+#include "qtest.h"
int tb_invalidated_flag;
diff --git a/cpus.c b/cpus.c
index 25ba621..ab8d67b 100644
--- a/cpus.c
+++ b/cpus.c
@@ -741,6 +741,48 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
return NULL;
}
+static void *qemu_dummy_cpu_thread_fn(void *arg)
+{
+#ifdef _WIN32
+ fprintf(stderr, "qtest is not supported under Windows\n");
+ exit(1);
+#else
+ CPUArchState *env = arg;
+ sigset_t waitset;
+ int r;
+
+ qemu_mutex_lock_iothread();
+ qemu_thread_get_self(env->thread);
+ env->thread_id = qemu_get_thread_id();
+
+ sigemptyset(&waitset);
+ sigaddset(&waitset, SIG_IPI);
+
+ /* signal CPU creation */
+ env->created = 1;
+ qemu_cond_signal(&qemu_cpu_cond);
+
+ cpu_single_env = env;
+ while (1) {
+ cpu_single_env = NULL;
+ qemu_mutex_unlock_iothread();
+ do {
+ int sig;
+ r = sigwait(&waitset, &sig);
+ } while (r == -1 && (errno == EAGAIN || errno == EINTR));
+ if (r == -1) {
+ perror("sigwait");
+ exit(1);
+ }
+ qemu_mutex_lock_iothread();
+ cpu_single_env = env;
+ qemu_wait_io_event_common(env);
+ }
+
+ return NULL;
+#endif
+}
+
static void tcg_exec_all(void);
static void *qemu_tcg_cpu_thread_fn(void *arg)
@@ -803,7 +845,7 @@ void qemu_cpu_kick(void *_env)
CPUArchState *env = _env;
qemu_cond_broadcast(env->halt_cond);
- if (kvm_enabled() && !env->thread_kicked) {
+ if (!tcg_enabled() && !env->thread_kicked) {
qemu_cpu_kick_thread(env);
env->thread_kicked = true;
}
@@ -832,7 +874,7 @@ int qemu_cpu_is_self(void *_env)
void qemu_mutex_lock_iothread(void)
{
- if (kvm_enabled()) {
+ if (!tcg_enabled()) {
qemu_mutex_lock(&qemu_global_mutex);
} else {
iothread_requesting_mutex = true;
@@ -947,6 +989,18 @@ static void qemu_kvm_start_vcpu(CPUArchState *env)
}
}
+static void qemu_dummy_start_vcpu(CPUArchState *env)
+{
+ env->thread = g_malloc0(sizeof(QemuThread));
+ env->halt_cond = g_malloc0(sizeof(QemuCond));
+ qemu_cond_init(env->halt_cond);
+ qemu_thread_create(env->thread, qemu_dummy_cpu_thread_fn, env,
+ QEMU_THREAD_JOINABLE);
+ while (env->created == 0) {
+ qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+ }
+}
+
void qemu_init_vcpu(void *_env)
{
CPUArchState *env = _env;
@@ -956,8 +1010,10 @@ void qemu_init_vcpu(void *_env)
env->stopped = 1;
if (kvm_enabled()) {
qemu_kvm_start_vcpu(env);
- } else {
+ } else if (tcg_enabled()) {
qemu_tcg_init_vcpu(env);
+ } else {
+ qemu_dummy_start_vcpu(env);
}
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 662f571..fe88939 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2715,6 +2715,14 @@ the @var{simple} tracing backend.
@end table
ETEXI
+DEF("qtest", HAS_ARG, QEMU_OPTION_qtest,
+ "-qtest CHR specify tracing options\n",
+ QEMU_ARCH_ALL)
+
+DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log,
+ "-qtest-log LOG specify tracing options\n",
+ QEMU_ARCH_ALL)
+
HXCOMM This is the last statement. Insert new options before this line!
STEXI
@end table
diff --git a/qtest.c b/qtest.c
new file mode 100644
index 0000000..46ebda1
--- /dev/null
+++ b/qtest.c
@@ -0,0 +1,354 @@
+/*
+ * Test Server
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qtest.h"
+#include "qemu-char.h"
+#include "ioport.h"
+#include "memory.h"
+#include "hw/irq.h"
+#include "sysemu.h"
+
+#define MAX_IRQ 256
+
+const char *qtest_chrdev;
+const char *qtest_log;
+int qtest_allowed = 0;
+
+static FILE *qtest_log_fp;
+static CharDriverState *qtest_chr;
+static GString *inbuf;
+static int irq_levels[MAX_IRQ];
+static struct timeval start_time;
+static bool qtest_opened;
+
+#define FMT_timeval "%" PRId64 ".%06" PRId64
+
+/**
+ * QTest Protocol
+ *
+ * Line based protocol, request/response based. Server can send async messages
+ * so clients should always handle many async messages before the response
+ * comes in.
+ *
+ * Valid requests
+ *
+ * > outb ADDR VALUE
+ * < OK
+ *
+ * > outw ADDR VALUE
+ * < OK
+ *
+ * > outl ADDR VALUE
+ * < OK
+ *
+ * > inb ADDR
+ * < OK VALUE
+ *
+ * > inw ADDR
+ * < OK VALUE
+ *
+ * > inl ADDR
+ * < OK VALUE
+ *
+ * > read ADDR SIZE
+ * < OK DATA
+ *
+ * > write ADDR SIZE DATA
+ * < OK
+ *
+ * Valid async messages:
+ *
+ * IRQ raise NUM
+ * IRQ lower NUM
+ *
+ * ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
+ *
+ * DATA is an arbitrarily long hex number prefixed with '0x'. If it's smaller
+ * than the expected size, the value will be zero filled at the end of the data
+ * sequence.
+ *
+ * NUM is an IRQ number.
+ */
+
+static int hex2nib(char ch)
+{
+ if (ch >= '0' && ch <= '9') {
+ return ch - '0';
+ } else if (ch >= 'a' && ch <= 'f') {
+ return 10 + (ch - 'a');
+ } else if (ch >= 'A' && ch <= 'F') {
+ return 10 + (ch - 'a');
+ } else {
+ return -1;
+ }
+}
+
+static void qtest_get_time(struct timeval *tv)
+{
+ gettimeofday(tv, NULL);
+ tv->tv_sec -= start_time.tv_sec;
+ tv->tv_usec -= start_time.tv_usec;
+ if (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec -= 1;
+ }
+}
+
+static void qtest_send_prefix(CharDriverState *chr)
+{
+ struct timeval tv;
+
+ if (!qtest_log_fp || !qtest_opened) {
+ return;
+ }
+
+ qtest_get_time(&tv);
+ fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
+ tv.tv_sec, tv.tv_usec);
+}
+
+static void qtest_send(CharDriverState *chr, const char *fmt, ...)
+{
+ va_list ap;
+ char buffer[1024];
+ size_t len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ qemu_chr_fe_write(chr, (uint8_t *)buffer, len);
+ if (qtest_log_fp && qtest_opened) {
+ fprintf(qtest_log_fp, "%s", buffer);
+ }
+}
+
+static void qtest_process_command(CharDriverState *chr, gchar **words)
+{
+ const gchar *command;
+
+ g_assert(words);
+
+ command = words[0];
+
+ if (qtest_log_fp) {
+ struct timeval tv;
+ int i;
+
+ qtest_get_time(&tv);
+ fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
+ tv.tv_sec, tv.tv_usec);
+ for (i = 0; words[i]; i++) {
+ fprintf(qtest_log_fp, " %s", words[i]);
+ }
+ fprintf(qtest_log_fp, "\n");
+ }
+
+ g_assert(command);
+ if (strcmp(words[0], "outb") == 0 ||
+ strcmp(words[0], "outw") == 0 ||
+ strcmp(words[0], "outl") == 0) {
+ uint16_t addr;
+ uint32_t value;
+
+ g_assert(words[1] && words[2]);
+ addr = strtol(words[1], NULL, 0);
+ value = strtol(words[2], NULL, 0);
+
+ if (words[0][3] == 'b') {
+ cpu_outb(addr, value);
+ } else if (words[0][3] == 'w') {
+ cpu_outw(addr, value);
+ } else if (words[0][3] == 'l') {
+ cpu_outl(addr, value);
+ }
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK\n");
+ } else if (strcmp(words[0], "inb") == 0 ||
+ strcmp(words[0], "inw") == 0 ||
+ strcmp(words[0], "inl") == 0) {
+ uint16_t addr;
+ uint32_t value = -1U;
+
+ g_assert(words[1]);
+ addr = strtol(words[1], NULL, 0);
+
+ if (words[0][2] == 'b') {
+ value = cpu_inb(addr);
+ } else if (words[0][2] == 'w') {
+ value = cpu_inw(addr);
+ } else if (words[0][2] == 'l') {
+ value = cpu_inl(addr);
+ }
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK 0x%04x\n", value);
+ } else if (strcmp(words[0], "read") == 0) {
+ uint64_t addr, len, i;
+ uint8_t *data;
+
+ g_assert(words[1] && words[2]);
+ addr = strtoul(words[1], NULL, 0);
+ len = strtoul(words[2], NULL, 0);
+
+ data = g_malloc(len);
+ cpu_physical_memory_read(addr, data, len);
+
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK 0x");
+ for (i = 0; i < len; i++) {
+ qtest_send(chr, "%02x", data[i]);
+ }
+ qtest_send(chr, "\n");
+
+ g_free(data);
+ } else if (strcmp(words[0], "write") == 0) {
+ uint64_t addr, len, i;
+ uint8_t *data;
+ size_t data_len;
+
+ g_assert(words[1] && words[2] && words[3]);
+ addr = strtoul(words[1], NULL, 0);
+ len = strtoul(words[2], NULL, 0);
+
+ data_len = strlen(words[3]);
+ if (data_len < 3) {
+ qtest_send(chr, "ERR invalid argument size\n");
+ return;
+ }
+
+ data = g_malloc(len);
+ for (i = 0; i < len; i++) {
+ if ((i * 2 + 4) <= data_len) {
+ data[i] = hex2nib(words[3][i * 2 + 2]) << 4;
+ data[i] |= hex2nib(words[3][i * 2 + 3]);
+ } else {
+ data[i] = 0;
+ }
+ }
+ cpu_physical_memory_write(addr, data, len);
+ g_free(data);
+
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK\n");
+ } else {
+ qtest_send_prefix(chr);
+ qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
+ }
+}
+
+static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
+{
+ char *end;
+
+ while ((end = strchr(inbuf->str, '\n')) != NULL) {
+ size_t offset;
+ GString *cmd;
+ gchar **words;
+
+ offset = end - inbuf->str;
+
+ cmd = g_string_new_len(inbuf->str, offset);
+ g_string_erase(inbuf, 0, offset + 1);
+
+ words = g_strsplit(cmd->str, " ", 0);
+ qtest_process_command(chr, words);
+ g_strfreev(words);
+
+ g_string_free(cmd, TRUE);
+ }
+}
+
+static void qtest_read(void *opaque, const uint8_t *buf, int size)
+{
+ CharDriverState *chr = opaque;
+
+ g_string_append_len(inbuf, (const gchar *)buf, size);
+ qtest_process_inbuf(chr, inbuf);
+}
+
+static int qtest_can_read(void *opaque)
+{
+ return 1024;
+}
+
+static void qtest_event(void *opaque, int event)
+{
+ int i;
+
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ qemu_system_reset(false);
+ for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
+ irq_levels[i] = 0;
+ }
+ gettimeofday(&start_time, NULL);
+ qtest_opened = true;
+ if (qtest_log_fp) {
+ fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
+ start_time.tv_sec, start_time.tv_usec);
+ }
+ break;
+ case CHR_EVENT_CLOSED:
+ qtest_opened = false;
+ if (qtest_log_fp) {
+ struct timeval tv;
+ qtest_get_time(&tv);
+ fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
+ tv.tv_sec, tv.tv_usec);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void qtest_set_irq(void *opaque, int irq, int level)
+{
+ CharDriverState *chr = qtest_chr;
+ bool changed;
+
+ changed = (irq_levels[irq] != level);
+ irq_levels[irq] = level;
+
+ if (changed) {
+ qtest_send_prefix(chr);
+ qtest_send(chr, "IRQ %s %d\n",
+ level ? "raise" : "lower", irq);
+ }
+}
+
+int qtest_init(void)
+{
+ CharDriverState *chr;
+
+ g_assert(qtest_chrdev != NULL);
+
+ chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
+
+ qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
+ qemu_chr_fe_set_echo(chr, true);
+
+ inbuf = g_string_new("");
+
+ if (qtest_log) {
+ if (strcmp(qtest_log, "none") != 0) {
+ qtest_log_fp = fopen(qtest_log, "w+");
+ }
+ } else {
+ qtest_log_fp = stderr;
+ }
+
+ qtest_chr = chr;
+
+ return 0;
+}
diff --git a/qtest.h b/qtest.h
new file mode 100644
index 0000000..1478343
--- /dev/null
+++ b/qtest.h
@@ -0,0 +1,35 @@
+/*
+ * Test Server
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QTEST_H
+#define QTEST_H
+
+#include "qemu-common.h"
+
+extern int qtest_allowed;
+extern const char *qtest_chrdev;
+extern const char *qtest_log;
+
+static inline bool qtest_enabled(void)
+{
+ return qtest_allowed;
+}
+
+static inline int qtest_available(void)
+{
+ return 1;
+}
+
+int qtest_init(void);
+
+#endif
diff --git a/scripts/qtest b/scripts/qtest
new file mode 100755
index 0000000..4ef6c1c
--- /dev/null
+++ b/scripts/qtest
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+export QTEST_QEMU_BINARY=$1
+shift
+"$@"
diff --git a/vl.c b/vl.c
index 0fccf50..e575401 100644
--- a/vl.c
+++ b/vl.c
@@ -152,6 +152,7 @@ int main(int argc, char **argv)
#ifdef CONFIG_VIRTFS
#include "fsdev/qemu-fsdev.h"
#endif
+#include "qtest.h"
#include "disas.h"
@@ -1312,7 +1313,7 @@ int qemu_shutdown_requested(void)
void qemu_kill_report(void)
{
- if (shutdown_signal != -1) {
+ if (!qtest_enabled() && shutdown_signal != -1) {
fprintf(stderr, "qemu: terminating on signal %d", shutdown_signal);
if (shutdown_pid == 0) {
/* This happens for eg ^C at the terminal, so it's worth
@@ -2098,6 +2099,7 @@ static struct {
{ "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
{ "xen", "Xen", xen_available, xen_init, &xen_allowed },
{ "kvm", "KVM", kvm_available, kvm_init, &kvm_allowed },
+ { "qtest", "QTest", qtest_available, qtest_init, &qtest_allowed },
};
static int configure_accelerator(void)
@@ -3181,6 +3183,12 @@ int main(int argc, char **argv, char **envp)
fclose(fp);
break;
}
+ case QEMU_OPTION_qtest:
+ qtest_chrdev = optarg;
+ break;
+ case QEMU_OPTION_qtest_log:
+ qtest_log = optarg;
+ break;
default:
os_parse_cmd_args(popt->index, optarg);
}
commit b93b63f574ccb451e82f81c6da7c39b3ecb4f24c
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Mar 28 15:42:01 2012 +0200
test makefile overhaul
This introduces new test reporting infrastructure based on
gtester and gtester-report.
Also, all existing tests are moved to tests/, and tests/Makefile
is reorganized to factor out the commonalities in the rules.
Signed-off-by: Anthony Liguori <aliguori at linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/check-qdict.c b/check-qdict.c
deleted file mode 100644
index fc0d276..0000000
--- a/check-qdict.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * QDict unit-tests.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * Authors:
- * Luiz Capitulino <lcapitulino at redhat.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- */
-#include <glib.h>
-
-#include "qint.h"
-#include "qdict.h"
-#include "qstring.h"
-#include "qemu-common.h"
-
-/*
- * Public Interface test-cases
- *
- * (with some violations to access 'private' data)
- */
-
-static void qdict_new_test(void)
-{
- QDict *qdict;
-
- qdict = qdict_new();
- g_assert(qdict != NULL);
- g_assert(qdict_size(qdict) == 0);
- g_assert(qdict->base.refcnt == 1);
- g_assert(qobject_type(QOBJECT(qdict)) == QTYPE_QDICT);
-
- // destroy doesn't exit yet
- g_free(qdict);
-}
-
-static void qdict_put_obj_test(void)
-{
- QInt *qi;
- QDict *qdict;
- QDictEntry *ent;
- const int num = 42;
-
- qdict = qdict_new();
-
- // key "" will have tdb hash 12345
- qdict_put_obj(qdict, "", QOBJECT(qint_from_int(num)));
-
- g_assert(qdict_size(qdict) == 1);
- ent = QLIST_FIRST(&qdict->table[12345 % QDICT_BUCKET_MAX]);
- qi = qobject_to_qint(ent->value);
- g_assert(qint_get_int(qi) == num);
-
- // destroy doesn't exit yet
- QDECREF(qi);
- g_free(ent->key);
- g_free(ent);
- g_free(qdict);
-}
-
-static void qdict_destroy_simple_test(void)
-{
- QDict *qdict;
-
- qdict = qdict_new();
- qdict_put_obj(qdict, "num", QOBJECT(qint_from_int(0)));
- qdict_put_obj(qdict, "str", QOBJECT(qstring_from_str("foo")));
-
- QDECREF(qdict);
-}
-
-static void qdict_get_test(void)
-{
- QInt *qi;
- QObject *obj;
- const int value = -42;
- const char *key = "test";
- QDict *tests_dict = qdict_new();
-
- qdict_put(tests_dict, key, qint_from_int(value));
-
- obj = qdict_get(tests_dict, key);
- g_assert(obj != NULL);
-
- qi = qobject_to_qint(obj);
- g_assert(qint_get_int(qi) == value);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_get_int_test(void)
-{
- int ret;
- const int value = 100;
- const char *key = "int";
- QDict *tests_dict = qdict_new();
-
- qdict_put(tests_dict, key, qint_from_int(value));
-
- ret = qdict_get_int(tests_dict, key);
- g_assert(ret == value);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_get_try_int_test(void)
-{
- int ret;
- const int value = 100;
- const char *key = "int";
- QDict *tests_dict = qdict_new();
-
- qdict_put(tests_dict, key, qint_from_int(value));
-
- ret = qdict_get_try_int(tests_dict, key, 0);
- g_assert(ret == value);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_get_str_test(void)
-{
- const char *p;
- const char *key = "key";
- const char *str = "string";
- QDict *tests_dict = qdict_new();
-
- qdict_put(tests_dict, key, qstring_from_str(str));
-
- p = qdict_get_str(tests_dict, key);
- g_assert(p != NULL);
- g_assert(strcmp(p, str) == 0);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_get_try_str_test(void)
-{
- const char *p;
- const char *key = "key";
- const char *str = "string";
- QDict *tests_dict = qdict_new();
-
- qdict_put(tests_dict, key, qstring_from_str(str));
-
- p = qdict_get_try_str(tests_dict, key);
- g_assert(p != NULL);
- g_assert(strcmp(p, str) == 0);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_haskey_not_test(void)
-{
- QDict *tests_dict = qdict_new();
- g_assert(qdict_haskey(tests_dict, "test") == 0);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_haskey_test(void)
-{
- const char *key = "test";
- QDict *tests_dict = qdict_new();
-
- qdict_put(tests_dict, key, qint_from_int(0));
- g_assert(qdict_haskey(tests_dict, key) == 1);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_del_test(void)
-{
- const char *key = "key test";
- QDict *tests_dict = qdict_new();
-
- qdict_put(tests_dict, key, qstring_from_str("foo"));
- g_assert(qdict_size(tests_dict) == 1);
-
- qdict_del(tests_dict, key);
-
- g_assert(qdict_size(tests_dict) == 0);
- g_assert(qdict_haskey(tests_dict, key) == 0);
-
- QDECREF(tests_dict);
-}
-
-static void qobject_to_qdict_test(void)
-{
- QDict *tests_dict = qdict_new();
- g_assert(qobject_to_qdict(QOBJECT(tests_dict)) == tests_dict);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_iterapi_test(void)
-{
- int count;
- const QDictEntry *ent;
- QDict *tests_dict = qdict_new();
-
- g_assert(qdict_first(tests_dict) == NULL);
-
- qdict_put(tests_dict, "key1", qint_from_int(1));
- qdict_put(tests_dict, "key2", qint_from_int(2));
- qdict_put(tests_dict, "key3", qint_from_int(3));
-
- count = 0;
- for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
- g_assert(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
- count++;
- }
-
- g_assert(count == qdict_size(tests_dict));
-
- /* Do it again to test restarting */
- count = 0;
- for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
- g_assert(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
- count++;
- }
-
- g_assert(count == qdict_size(tests_dict));
-
- QDECREF(tests_dict);
-}
-
-/*
- * Errors test-cases
- */
-
-static void qdict_put_exists_test(void)
-{
- int value;
- const char *key = "exists";
- QDict *tests_dict = qdict_new();
-
- qdict_put(tests_dict, key, qint_from_int(1));
- qdict_put(tests_dict, key, qint_from_int(2));
-
- value = qdict_get_int(tests_dict, key);
- g_assert(value == 2);
-
- g_assert(qdict_size(tests_dict) == 1);
-
- QDECREF(tests_dict);
-}
-
-static void qdict_get_not_exists_test(void)
-{
- QDict *tests_dict = qdict_new();
- g_assert(qdict_get(tests_dict, "foo") == NULL);
-
- QDECREF(tests_dict);
-}
-
-/*
- * Stress test-case
- *
- * This is a lot big for a unit-test, but there is no other place
- * to have it.
- */
-
-static void remove_dots(char *string)
-{
- char *p = strchr(string, ':');
- if (p)
- *p = '\0';
-}
-
-static QString *read_line(FILE *file, char *key)
-{
- char value[128];
-
- if (fscanf(file, "%127s%127s", key, value) == EOF) {
- return NULL;
- }
- remove_dots(key);
- return qstring_from_str(value);
-}
-
-#define reset_file(file) fseek(file, 0L, SEEK_SET)
-
-static void qdict_stress_test(void)
-{
- size_t lines;
- char key[128];
- FILE *test_file;
- QDict *qdict;
- QString *value;
- const char *test_file_path = "qdict-test-data.txt";
-
- test_file = fopen(test_file_path, "r");
- g_assert(test_file != NULL);
-
- // Create the dict
- qdict = qdict_new();
- g_assert(qdict != NULL);
-
- // Add everything from the test file
- for (lines = 0;; lines++) {
- value = read_line(test_file, key);
- if (!value)
- break;
-
- qdict_put(qdict, key, value);
- }
- g_assert(qdict_size(qdict) == lines);
-
- // Check if everything is really in there
- reset_file(test_file);
- for (;;) {
- const char *str1, *str2;
-
- value = read_line(test_file, key);
- if (!value)
- break;
-
- str1 = qstring_get_str(value);
-
- str2 = qdict_get_str(qdict, key);
- g_assert(str2 != NULL);
-
- g_assert(strcmp(str1, str2) == 0);
-
- QDECREF(value);
- }
-
- // Delete everything
- reset_file(test_file);
- for (;;) {
- value = read_line(test_file, key);
- if (!value)
- break;
-
- qdict_del(qdict, key);
- QDECREF(value);
-
- g_assert(qdict_haskey(qdict, key) == 0);
- }
- fclose(test_file);
-
- g_assert(qdict_size(qdict) == 0);
- QDECREF(qdict);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/public/new", qdict_new_test);
- g_test_add_func("/public/put_obj", qdict_put_obj_test);
- g_test_add_func("/public/destroy_simple", qdict_destroy_simple_test);
-
- /* Continue, but now with fixtures */
- g_test_add_func("/public/get", qdict_get_test);
- g_test_add_func("/public/get_int", qdict_get_int_test);
- g_test_add_func("/public/get_try_int", qdict_get_try_int_test);
- g_test_add_func("/public/get_str", qdict_get_str_test);
- g_test_add_func("/public/get_try_str", qdict_get_try_str_test);
- g_test_add_func("/public/haskey_not", qdict_haskey_not_test);
- g_test_add_func("/public/haskey", qdict_haskey_test);
- g_test_add_func("/public/del", qdict_del_test);
- g_test_add_func("/public/to_qdict", qobject_to_qdict_test);
- g_test_add_func("/public/iterapi", qdict_iterapi_test);
-
- g_test_add_func("/errors/put_exists", qdict_put_exists_test);
- g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
-
- /* The Big one */
- if (g_test_slow()) {
- g_test_add_func("/stress/test", qdict_stress_test);
- }
-
- return g_test_run();
-}
diff --git a/check-qfloat.c b/check-qfloat.c
deleted file mode 100644
index cdc66ea..0000000
--- a/check-qfloat.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * QFloat unit-tests.
- *
- * Copyright IBM, Corp. 2009
- *
- * Authors:
- * Anthony Liguori <aliguori at us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-#include <glib.h>
-
-#include "qfloat.h"
-#include "qemu-common.h"
-
-/*
- * Public Interface test-cases
- *
- * (with some violations to access 'private' data)
- */
-
-static void qfloat_from_double_test(void)
-{
- QFloat *qf;
- const double value = -42.23423;
-
- qf = qfloat_from_double(value);
- g_assert(qf != NULL);
- g_assert(qf->value == value);
- g_assert(qf->base.refcnt == 1);
- g_assert(qobject_type(QOBJECT(qf)) == QTYPE_QFLOAT);
-
- // destroy doesn't exit yet
- g_free(qf);
-}
-
-static void qfloat_destroy_test(void)
-{
- QFloat *qf = qfloat_from_double(0.0);
- QDECREF(qf);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/public/from_double", qfloat_from_double_test);
- g_test_add_func("/public/destroy", qfloat_destroy_test);
-
- return g_test_run();
-}
diff --git a/check-qint.c b/check-qint.c
deleted file mode 100644
index 5a27119..0000000
--- a/check-qint.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * QInt unit-tests.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * Authors:
- * Luiz Capitulino <lcapitulino at redhat.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- */
-#include <glib.h>
-
-#include "qint.h"
-#include "qemu-common.h"
-
-/*
- * Public Interface test-cases
- *
- * (with some violations to access 'private' data)
- */
-
-static void qint_from_int_test(void)
-{
- QInt *qi;
- const int value = -42;
-
- qi = qint_from_int(value);
- g_assert(qi != NULL);
- g_assert(qi->value == value);
- g_assert(qi->base.refcnt == 1);
- g_assert(qobject_type(QOBJECT(qi)) == QTYPE_QINT);
-
- // destroy doesn't exit yet
- g_free(qi);
-}
-
-static void qint_destroy_test(void)
-{
- QInt *qi = qint_from_int(0);
- QDECREF(qi);
-}
-
-static void qint_from_int64_test(void)
-{
- QInt *qi;
- const int64_t value = 0x1234567890abcdefLL;
-
- qi = qint_from_int(value);
- g_assert((int64_t) qi->value == value);
-
- QDECREF(qi);
-}
-
-static void qint_get_int_test(void)
-{
- QInt *qi;
- const int value = 123456;
-
- qi = qint_from_int(value);
- g_assert(qint_get_int(qi) == value);
-
- QDECREF(qi);
-}
-
-static void qobject_to_qint_test(void)
-{
- QInt *qi;
-
- qi = qint_from_int(0);
- g_assert(qobject_to_qint(QOBJECT(qi)) == qi);
-
- QDECREF(qi);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/public/from_int", qint_from_int_test);
- g_test_add_func("/public/destroy", qint_destroy_test);
- g_test_add_func("/public/from_int64", qint_from_int64_test);
- g_test_add_func("/public/get_int", qint_get_int_test);
- g_test_add_func("/public/to_qint", qobject_to_qint_test);
-
- return g_test_run();
-}
diff --git a/check-qjson.c b/check-qjson.c
deleted file mode 100644
index 526e25e..0000000
--- a/check-qjson.c
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * Copyright IBM, Corp. 2009
- *
- * Authors:
- * Anthony Liguori <aliguori at us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-#include <glib.h>
-
-#include "qstring.h"
-#include "qint.h"
-#include "qdict.h"
-#include "qlist.h"
-#include "qfloat.h"
-#include "qbool.h"
-#include "qjson.h"
-
-#include "qemu-common.h"
-
-static void escaped_string(void)
-{
- int i;
- struct {
- const char *encoded;
- const char *decoded;
- int skip;
- } test_cases[] = {
- { "\"\\b\"", "\b" },
- { "\"\\f\"", "\f" },
- { "\"\\n\"", "\n" },
- { "\"\\r\"", "\r" },
- { "\"\\t\"", "\t" },
- { "\"/\"", "/" },
- { "\"\\/\"", "/", .skip = 1 },
- { "\"\\\\\"", "\\" },
- { "\"\\\"\"", "\"" },
- { "\"hello world \\\"embedded string\\\"\"",
- "hello world \"embedded string\"" },
- { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
- { "\"single byte utf-8 \\u0020\"", "single byte utf-8 ", .skip = 1 },
- { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
- { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
- {}
- };
-
- for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
- QString *str;
-
- obj = qobject_from_json(test_cases[i].encoded);
-
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
-
- str = qobject_to_qstring(obj);
- g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].decoded);
-
- if (test_cases[i].skip == 0) {
- str = qobject_to_json(obj);
- g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].encoded);
- qobject_decref(obj);
- }
-
- QDECREF(str);
- }
-}
-
-static void simple_string(void)
-{
- int i;
- struct {
- const char *encoded;
- const char *decoded;
- } test_cases[] = {
- { "\"hello world\"", "hello world" },
- { "\"the quick brown fox jumped over the fence\"",
- "the quick brown fox jumped over the fence" },
- {}
- };
-
- for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
- QString *str;
-
- obj = qobject_from_json(test_cases[i].encoded);
-
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
-
- str = qobject_to_qstring(obj);
- g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
-
- str = qobject_to_json(obj);
- g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
-
- qobject_decref(obj);
-
- QDECREF(str);
- }
-}
-
-static void single_quote_string(void)
-{
- int i;
- struct {
- const char *encoded;
- const char *decoded;
- } test_cases[] = {
- { "'hello world'", "hello world" },
- { "'the quick brown fox \\' jumped over the fence'",
- "the quick brown fox ' jumped over the fence" },
- {}
- };
-
- for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
- QString *str;
-
- obj = qobject_from_json(test_cases[i].encoded);
-
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
-
- str = qobject_to_qstring(obj);
- g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
-
- QDECREF(str);
- }
-}
-
-static void vararg_string(void)
-{
- int i;
- struct {
- const char *decoded;
- } test_cases[] = {
- { "hello world" },
- { "the quick brown fox jumped over the fence" },
- {}
- };
-
- for (i = 0; test_cases[i].decoded; i++) {
- QObject *obj;
- QString *str;
-
- obj = qobject_from_jsonf("%s", test_cases[i].decoded);
-
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
-
- str = qobject_to_qstring(obj);
- g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
-
- QDECREF(str);
- }
-}
-
-static void simple_number(void)
-{
- int i;
- struct {
- const char *encoded;
- int64_t decoded;
- int skip;
- } test_cases[] = {
- { "0", 0 },
- { "1234", 1234 },
- { "1", 1 },
- { "-32", -32 },
- { "-0", 0, .skip = 1 },
- { },
- };
-
- for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
- QInt *qint;
-
- obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QINT);
-
- qint = qobject_to_qint(obj);
- g_assert(qint_get_int(qint) == test_cases[i].decoded);
- if (test_cases[i].skip == 0) {
- QString *str;
-
- str = qobject_to_json(obj);
- g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
- QDECREF(str);
- }
-
- QDECREF(qint);
- }
-}
-
-static void float_number(void)
-{
- int i;
- struct {
- const char *encoded;
- double decoded;
- int skip;
- } test_cases[] = {
- { "32.43", 32.43 },
- { "0.222", 0.222 },
- { "-32.12313", -32.12313 },
- { "-32.20e-10", -32.20e-10, .skip = 1 },
- { },
- };
-
- for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
- QFloat *qfloat;
-
- obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QFLOAT);
-
- qfloat = qobject_to_qfloat(obj);
- g_assert(qfloat_get_double(qfloat) == test_cases[i].decoded);
-
- if (test_cases[i].skip == 0) {
- QString *str;
-
- str = qobject_to_json(obj);
- g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
- QDECREF(str);
- }
-
- QDECREF(qfloat);
- }
-}
-
-static void vararg_number(void)
-{
- QObject *obj;
- QInt *qint;
- QFloat *qfloat;
- int value = 0x2342;
- int64_t value64 = 0x2342342343LL;
- double valuef = 2.323423423;
-
- obj = qobject_from_jsonf("%d", value);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QINT);
-
- qint = qobject_to_qint(obj);
- g_assert(qint_get_int(qint) == value);
-
- QDECREF(qint);
-
- obj = qobject_from_jsonf("%" PRId64, value64);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QINT);
-
- qint = qobject_to_qint(obj);
- g_assert(qint_get_int(qint) == value64);
-
- QDECREF(qint);
-
- obj = qobject_from_jsonf("%f", valuef);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QFLOAT);
-
- qfloat = qobject_to_qfloat(obj);
- g_assert(qfloat_get_double(qfloat) == valuef);
-
- QDECREF(qfloat);
-}
-
-static void keyword_literal(void)
-{
- QObject *obj;
- QBool *qbool;
- QString *str;
-
- obj = qobject_from_json("true");
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
-
- qbool = qobject_to_qbool(obj);
- g_assert(qbool_get_int(qbool) != 0);
-
- str = qobject_to_json(obj);
- g_assert(strcmp(qstring_get_str(str), "true") == 0);
- QDECREF(str);
-
- QDECREF(qbool);
-
- obj = qobject_from_json("false");
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
-
- qbool = qobject_to_qbool(obj);
- g_assert(qbool_get_int(qbool) == 0);
-
- str = qobject_to_json(obj);
- g_assert(strcmp(qstring_get_str(str), "false") == 0);
- QDECREF(str);
-
- QDECREF(qbool);
-
- obj = qobject_from_jsonf("%i", false);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
-
- qbool = qobject_to_qbool(obj);
- g_assert(qbool_get_int(qbool) == 0);
-
- QDECREF(qbool);
-
- obj = qobject_from_jsonf("%i", true);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
-
- qbool = qobject_to_qbool(obj);
- g_assert(qbool_get_int(qbool) != 0);
-
- QDECREF(qbool);
-}
-
-typedef struct LiteralQDictEntry LiteralQDictEntry;
-typedef struct LiteralQObject LiteralQObject;
-
-struct LiteralQObject
-{
- int type;
- union {
- int64_t qint;
- const char *qstr;
- LiteralQDictEntry *qdict;
- LiteralQObject *qlist;
- } value;
-};
-
-struct LiteralQDictEntry
-{
- const char *key;
- LiteralQObject value;
-};
-
-#define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
-#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
-#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
-#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
-
-typedef struct QListCompareHelper
-{
- int index;
- LiteralQObject *objs;
- int result;
-} QListCompareHelper;
-
-static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
-
-static void compare_helper(QObject *obj, void *opaque)
-{
- QListCompareHelper *helper = opaque;
-
- if (helper->result == 0) {
- return;
- }
-
- if (helper->objs[helper->index].type == QTYPE_NONE) {
- helper->result = 0;
- return;
- }
-
- helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
-}
-
-static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
-{
- if (lhs->type != qobject_type(rhs)) {
- return 0;
- }
-
- switch (lhs->type) {
- case QTYPE_QINT:
- return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
- case QTYPE_QSTRING:
- return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
- case QTYPE_QDICT: {
- int i;
-
- for (i = 0; lhs->value.qdict[i].key; i++) {
- QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
-
- if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
- return 0;
- }
- }
-
- return 1;
- }
- case QTYPE_QLIST: {
- QListCompareHelper helper;
-
- helper.index = 0;
- helper.objs = lhs->value.qlist;
- helper.result = 1;
-
- qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
-
- return helper.result;
- }
- default:
- break;
- }
-
- return 0;
-}
-
-static void simple_dict(void)
-{
- int i;
- struct {
- const char *encoded;
- LiteralQObject decoded;
- } test_cases[] = {
- {
- .encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
- .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
- { "foo", QLIT_QINT(42) },
- { "bar", QLIT_QSTR("hello world") },
- { }
- })),
- }, {
- .encoded = "{}",
- .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
- { }
- })),
- }, {
- .encoded = "{\"foo\": 43}",
- .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
- { "foo", QLIT_QINT(43) },
- { }
- })),
- },
- { }
- };
-
- for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
- QString *str;
-
- obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QDICT);
-
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
-
- str = qobject_to_json(obj);
- qobject_decref(obj);
-
- obj = qobject_from_json(qstring_get_str(str));
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QDICT);
-
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
- qobject_decref(obj);
- QDECREF(str);
- }
-}
-
-static void simple_list(void)
-{
- int i;
- struct {
- const char *encoded;
- LiteralQObject decoded;
- } test_cases[] = {
- {
- .encoded = "[43,42]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
- QLIT_QINT(43),
- QLIT_QINT(42),
- { }
- })),
- },
- {
- .encoded = "[43]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
- QLIT_QINT(43),
- { }
- })),
- },
- {
- .encoded = "[]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
- { }
- })),
- },
- {
- .encoded = "[{}]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
- QLIT_QDICT(((LiteralQDictEntry[]){
- {},
- })),
- {},
- })),
- },
- { }
- };
-
- for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
- QString *str;
-
- obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
-
- str = qobject_to_json(obj);
- qobject_decref(obj);
-
- obj = qobject_from_json(qstring_get_str(str));
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
- qobject_decref(obj);
- QDECREF(str);
- }
-}
-
-static void simple_whitespace(void)
-{
- int i;
- struct {
- const char *encoded;
- LiteralQObject decoded;
- } test_cases[] = {
- {
- .encoded = " [ 43 , 42 ]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
- QLIT_QINT(43),
- QLIT_QINT(42),
- { }
- })),
- },
- {
- .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
- QLIT_QINT(43),
- QLIT_QDICT(((LiteralQDictEntry[]){
- { "h", QLIT_QSTR("b") },
- { }})),
- QLIT_QLIST(((LiteralQObject[]){
- { }})),
- QLIT_QINT(42),
- { }
- })),
- },
- {
- .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
- QLIT_QINT(43),
- QLIT_QDICT(((LiteralQDictEntry[]){
- { "h", QLIT_QSTR("b") },
- { "a", QLIT_QINT(32) },
- { }})),
- QLIT_QLIST(((LiteralQObject[]){
- { }})),
- QLIT_QINT(42),
- { }
- })),
- },
- { }
- };
-
- for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
- QString *str;
-
- obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
-
- str = qobject_to_json(obj);
- qobject_decref(obj);
-
- obj = qobject_from_json(qstring_get_str(str));
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
-
- qobject_decref(obj);
- QDECREF(str);
- }
-}
-
-static void simple_varargs(void)
-{
- QObject *embedded_obj;
- QObject *obj;
- LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
- QLIT_QINT(1),
- QLIT_QINT(2),
- QLIT_QLIST(((LiteralQObject[]){
- QLIT_QINT(32),
- QLIT_QINT(42),
- {}})),
- {}}));
-
- embedded_obj = qobject_from_json("[32, 42]");
- g_assert(embedded_obj != NULL);
-
- obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
- g_assert(obj != NULL);
-
- g_assert(compare_litqobj_to_qobj(&decoded, obj) == 1);
-
- qobject_decref(obj);
-}
-
-static void empty_input(void)
-{
- const char *empty = "";
-
- QObject *obj = qobject_from_json(empty);
- g_assert(obj == NULL);
-}
-
-static void unterminated_string(void)
-{
- QObject *obj = qobject_from_json("\"abc");
- g_assert(obj == NULL);
-}
-
-static void unterminated_sq_string(void)
-{
- QObject *obj = qobject_from_json("'abc");
- g_assert(obj == NULL);
-}
-
-static void unterminated_escape(void)
-{
- QObject *obj = qobject_from_json("\"abc\\\"");
- g_assert(obj == NULL);
-}
-
-static void unterminated_array(void)
-{
- QObject *obj = qobject_from_json("[32");
- g_assert(obj == NULL);
-}
-
-static void unterminated_array_comma(void)
-{
- QObject *obj = qobject_from_json("[32,");
- g_assert(obj == NULL);
-}
-
-static void invalid_array_comma(void)
-{
- QObject *obj = qobject_from_json("[32,}");
- g_assert(obj == NULL);
-}
-
-static void unterminated_dict(void)
-{
- QObject *obj = qobject_from_json("{'abc':32");
- g_assert(obj == NULL);
-}
-
-static void unterminated_dict_comma(void)
-{
- QObject *obj = qobject_from_json("{'abc':32,");
- g_assert(obj == NULL);
-}
-
-static void invalid_dict_comma(void)
-{
- QObject *obj = qobject_from_json("{'abc':32,}");
- g_assert(obj == NULL);
-}
-
-static void unterminated_literal(void)
-{
- QObject *obj = qobject_from_json("nul");
- g_assert(obj == NULL);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/literals/string/simple", simple_string);
- g_test_add_func("/literals/string/escaped", escaped_string);
- g_test_add_func("/literals/string/single_quote", single_quote_string);
- g_test_add_func("/literals/string/vararg", vararg_string);
-
- g_test_add_func("/literals/number/simple", simple_number);
- g_test_add_func("/literals/number/float", float_number);
- g_test_add_func("/literals/number/vararg", vararg_number);
-
- g_test_add_func("/literals/keyword", keyword_literal);
-
- g_test_add_func("/dicts/simple_dict", simple_dict);
- g_test_add_func("/lists/simple_list", simple_list);
-
- g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
-
- g_test_add_func("/varargs/simple_varargs", simple_varargs);
-
- g_test_add_func("/errors/empty_input", empty_input);
- g_test_add_func("/errors/unterminated/string", unterminated_string);
- g_test_add_func("/errors/unterminated/escape", unterminated_escape);
- g_test_add_func("/errors/unterminated/sq_string", unterminated_sq_string);
- g_test_add_func("/errors/unterminated/array", unterminated_array);
- g_test_add_func("/errors/unterminated/array_comma", unterminated_array_comma);
- g_test_add_func("/errors/unterminated/dict", unterminated_dict);
- g_test_add_func("/errors/unterminated/dict_comma", unterminated_dict_comma);
- g_test_add_func("/errors/invalid_array_comma", invalid_array_comma);
- g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma);
- g_test_add_func("/errors/unterminated/literal", unterminated_literal);
-
- return g_test_run();
-}
diff --git a/check-qlist.c b/check-qlist.c
deleted file mode 100644
index 501ba26..0000000
--- a/check-qlist.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * QList unit-tests.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * Authors:
- * Luiz Capitulino <lcapitulino at redhat.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- */
-#include <glib.h>
-
-#include "qint.h"
-#include "qlist.h"
-
-/*
- * Public Interface test-cases
- *
- * (with some violations to access 'private' data)
- */
-
-static void qlist_new_test(void)
-{
- QList *qlist;
-
- qlist = qlist_new();
- g_assert(qlist != NULL);
- g_assert(qlist->base.refcnt == 1);
- g_assert(qobject_type(QOBJECT(qlist)) == QTYPE_QLIST);
-
- // destroy doesn't exist yet
- g_free(qlist);
-}
-
-static void qlist_append_test(void)
-{
- QInt *qi;
- QList *qlist;
- QListEntry *entry;
-
- qi = qint_from_int(42);
-
- qlist = qlist_new();
- qlist_append(qlist, qi);
-
- entry = QTAILQ_FIRST(&qlist->head);
- g_assert(entry != NULL);
- g_assert(entry->value == QOBJECT(qi));
-
- // destroy doesn't exist yet
- QDECREF(qi);
- g_free(entry);
- g_free(qlist);
-}
-
-static void qobject_to_qlist_test(void)
-{
- QList *qlist;
-
- qlist = qlist_new();
-
- g_assert(qobject_to_qlist(QOBJECT(qlist)) == qlist);
-
- // destroy doesn't exist yet
- g_free(qlist);
-}
-
-static void qlist_destroy_test(void)
-{
- int i;
- QList *qlist;
-
- qlist = qlist_new();
-
- for (i = 0; i < 42; i++)
- qlist_append(qlist, qint_from_int(i));
-
- QDECREF(qlist);
-}
-
-static int iter_called;
-static const int iter_max = 42;
-
-static void iter_func(QObject *obj, void *opaque)
-{
- QInt *qi;
-
- g_assert(opaque == NULL);
-
- qi = qobject_to_qint(obj);
- g_assert(qi != NULL);
- g_assert((qint_get_int(qi) >= 0) && (qint_get_int(qi) <= iter_max));
-
- iter_called++;
-}
-
-static void qlist_iter_test(void)
-{
- int i;
- QList *qlist;
-
- qlist = qlist_new();
-
- for (i = 0; i < iter_max; i++)
- qlist_append(qlist, qint_from_int(i));
-
- iter_called = 0;
- qlist_iter(qlist, iter_func, NULL);
-
- g_assert(iter_called == iter_max);
-
- QDECREF(qlist);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/public/new", qlist_new_test);
- g_test_add_func("/public/append", qlist_append_test);
- g_test_add_func("/public/to_qlist", qobject_to_qlist_test);
- g_test_add_func("/public/destroy", qlist_destroy_test);
- g_test_add_func("/public/iter", qlist_iter_test);
-
- return g_test_run();
-}
diff --git a/check-qstring.c b/check-qstring.c
deleted file mode 100644
index addad6c..0000000
--- a/check-qstring.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * QString unit-tests.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * Authors:
- * Luiz Capitulino <lcapitulino at redhat.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- */
-#include <glib.h>
-
-#include "qstring.h"
-#include "qemu-common.h"
-
-/*
- * Public Interface test-cases
- *
- * (with some violations to access 'private' data)
- */
-
-static void qstring_from_str_test(void)
-{
- QString *qstring;
- const char *str = "QEMU";
-
- qstring = qstring_from_str(str);
- g_assert(qstring != NULL);
- g_assert(qstring->base.refcnt == 1);
- g_assert(strcmp(str, qstring->string) == 0);
- g_assert(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
-
- // destroy doesn't exit yet
- g_free(qstring->string);
- g_free(qstring);
-}
-
-static void qstring_destroy_test(void)
-{
- QString *qstring = qstring_from_str("destroy test");
- QDECREF(qstring);
-}
-
-static void qstring_get_str_test(void)
-{
- QString *qstring;
- const char *ret_str;
- const char *str = "QEMU/KVM";
-
- qstring = qstring_from_str(str);
- ret_str = qstring_get_str(qstring);
- g_assert(strcmp(ret_str, str) == 0);
-
- QDECREF(qstring);
-}
-
-static void qstring_append_chr_test(void)
-{
- int i;
- QString *qstring;
- const char *str = "qstring append char unit-test";
-
- qstring = qstring_new();
-
- for (i = 0; str[i]; i++)
- qstring_append_chr(qstring, str[i]);
-
- g_assert(strcmp(str, qstring_get_str(qstring)) == 0);
- QDECREF(qstring);
-}
-
-static void qstring_from_substr_test(void)
-{
- QString *qs;
-
- qs = qstring_from_substr("virtualization", 3, 9);
- g_assert(qs != NULL);
- g_assert(strcmp(qstring_get_str(qs), "tualiza") == 0);
-
- QDECREF(qs);
-}
-
-
-static void qobject_to_qstring_test(void)
-{
- QString *qstring;
-
- qstring = qstring_from_str("foo");
- g_assert(qobject_to_qstring(QOBJECT(qstring)) == qstring);
-
- QDECREF(qstring);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/public/from_str", qstring_from_str_test);
- g_test_add_func("/public/destroy", qstring_destroy_test);
- g_test_add_func("/public/get_str", qstring_get_str_test);
- g_test_add_func("/public/append_chr", qstring_append_chr_test);
- g_test_add_func("/public/from_substr", qstring_from_substr_test);
- g_test_add_func("/public/to_qstring", qobject_to_qstring_test);
-
- return g_test_run();
-}
diff --git a/rules.mak b/rules.mak
index 04a9198..c30093c 100644
--- a/rules.mak
+++ b/rules.mak
@@ -47,7 +47,7 @@ quiet-command = $(if $(V),$1,$(if $(2), at echo $2 && $1, @$1))
cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \
>/dev/null 2>&1 && echo OK), $2, $3)
-VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi
+VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi %.sh
set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1)))
# find-in-path
diff --git a/scripts/gtester-cat b/scripts/gtester-cat
new file mode 100755
index 0000000..061a952
--- /dev/null
+++ b/scripts/gtester-cat
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+# Anthony Liguori <aliguori at us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2 or later.
+# See the COPYING file in the top-level directory.
+
+cat <<EOF
+<?xml version="1.0"?>
+<gtester>
+ <info>
+ <package>qemu</package>
+ <version>0.0</version>
+ <revision>rev</revision>
+ </info>
+EOF
+
+sed \
+ -e '/<?xml/d' \
+ -e '/^<gtester>$/d' \
+ -e '/<info>/,/<\/info>/d' \
+ -e '$b' \
+ -e '/^<\/gtester>$/d' "$@"
diff --git a/test-coroutine.c b/test-coroutine.c
deleted file mode 100644
index e5d14eb..0000000
--- a/test-coroutine.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Coroutine tests
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#include <glib.h>
-#include "qemu-coroutine.h"
-
-/*
- * Check that qemu_in_coroutine() works
- */
-
-static void coroutine_fn verify_in_coroutine(void *opaque)
-{
- g_assert(qemu_in_coroutine());
-}
-
-static void test_in_coroutine(void)
-{
- Coroutine *coroutine;
-
- g_assert(!qemu_in_coroutine());
-
- coroutine = qemu_coroutine_create(verify_in_coroutine);
- qemu_coroutine_enter(coroutine, NULL);
-}
-
-/*
- * Check that qemu_coroutine_self() works
- */
-
-static void coroutine_fn verify_self(void *opaque)
-{
- g_assert(qemu_coroutine_self() == opaque);
-}
-
-static void test_self(void)
-{
- Coroutine *coroutine;
-
- coroutine = qemu_coroutine_create(verify_self);
- qemu_coroutine_enter(coroutine, coroutine);
-}
-
-/*
- * Check that coroutines may nest multiple levels
- */
-
-typedef struct {
- unsigned int n_enter; /* num coroutines entered */
- unsigned int n_return; /* num coroutines returned */
- unsigned int max; /* maximum level of nesting */
-} NestData;
-
-static void coroutine_fn nest(void *opaque)
-{
- NestData *nd = opaque;
-
- nd->n_enter++;
-
- if (nd->n_enter < nd->max) {
- Coroutine *child;
-
- child = qemu_coroutine_create(nest);
- qemu_coroutine_enter(child, nd);
- }
-
- nd->n_return++;
-}
-
-static void test_nesting(void)
-{
- Coroutine *root;
- NestData nd = {
- .n_enter = 0,
- .n_return = 0,
- .max = 128,
- };
-
- root = qemu_coroutine_create(nest);
- qemu_coroutine_enter(root, &nd);
-
- /* Must enter and return from max nesting level */
- g_assert_cmpint(nd.n_enter, ==, nd.max);
- g_assert_cmpint(nd.n_return, ==, nd.max);
-}
-
-/*
- * Check that yield/enter transfer control correctly
- */
-
-static void coroutine_fn yield_5_times(void *opaque)
-{
- bool *done = opaque;
- int i;
-
- for (i = 0; i < 5; i++) {
- qemu_coroutine_yield();
- }
- *done = true;
-}
-
-static void test_yield(void)
-{
- Coroutine *coroutine;
- bool done = false;
- int i = -1; /* one extra time to return from coroutine */
-
- coroutine = qemu_coroutine_create(yield_5_times);
- while (!done) {
- qemu_coroutine_enter(coroutine, &done);
- i++;
- }
- g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
-}
-
-/*
- * Check that creation, enter, and return work
- */
-
-static void coroutine_fn set_and_exit(void *opaque)
-{
- bool *done = opaque;
-
- *done = true;
-}
-
-static void test_lifecycle(void)
-{
- Coroutine *coroutine;
- bool done = false;
-
- /* Create, enter, and return from coroutine */
- coroutine = qemu_coroutine_create(set_and_exit);
- qemu_coroutine_enter(coroutine, &done);
- g_assert(done); /* expect done to be true (first time) */
-
- /* Repeat to check that no state affects this test */
- done = false;
- coroutine = qemu_coroutine_create(set_and_exit);
- qemu_coroutine_enter(coroutine, &done);
- g_assert(done); /* expect done to be true (second time) */
-}
-
-/*
- * Lifecycle benchmark
- */
-
-static void coroutine_fn empty_coroutine(void *opaque)
-{
- /* Do nothing */
-}
-
-static void perf_lifecycle(void)
-{
- Coroutine *coroutine;
- unsigned int i, max;
- double duration;
-
- max = 1000000;
-
- g_test_timer_start();
- for (i = 0; i < max; i++) {
- coroutine = qemu_coroutine_create(empty_coroutine);
- qemu_coroutine_enter(coroutine, NULL);
- }
- duration = g_test_timer_elapsed();
-
- g_test_message("Lifecycle %u iterations: %f s\n", max, duration);
-}
-
-static void perf_nesting(void)
-{
- unsigned int i, maxcycles, maxnesting;
- double duration;
-
- maxcycles = 100000000;
- maxnesting = 20000;
- Coroutine *root;
- NestData nd = {
- .n_enter = 0,
- .n_return = 0,
- .max = maxnesting,
- };
-
- g_test_timer_start();
- for (i = 0; i < maxcycles; i++) {
- root = qemu_coroutine_create(nest);
- qemu_coroutine_enter(root, &nd);
- }
- duration = g_test_timer_elapsed();
-
- g_test_message("Nesting %u iterations of %u depth each: %f s\n",
- maxcycles, maxnesting, duration);
-}
-
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
- g_test_add_func("/basic/lifecycle", test_lifecycle);
- g_test_add_func("/basic/yield", test_yield);
- g_test_add_func("/basic/nesting", test_nesting);
- g_test_add_func("/basic/self", test_self);
- g_test_add_func("/basic/in_coroutine", test_in_coroutine);
- if (g_test_perf()) {
- g_test_add_func("/perf/lifecycle", perf_lifecycle);
- g_test_add_func("/perf/nesting", perf_nesting);
- }
- return g_test_run();
-}
diff --git a/test-qmp-commands.c b/test-qmp-commands.c
deleted file mode 100644
index 60cbf01..0000000
--- a/test-qmp-commands.c
+++ /dev/null
@@ -1,139 +0,0 @@
-#include <glib.h>
-#include "qemu-objects.h"
-#include "test-qmp-commands.h"
-#include "qapi/qmp-core.h"
-#include "module.h"
-
-void qmp_user_def_cmd(Error **errp)
-{
-}
-
-void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
-{
-}
-
-UserDefTwo * qmp_user_def_cmd2(UserDefOne * ud1a, UserDefOne * ud1b, Error **errp)
-{
- UserDefTwo *ret;
- UserDefOne *ud1c = g_malloc0(sizeof(UserDefOne));
- UserDefOne *ud1d = g_malloc0(sizeof(UserDefOne));
-
- ud1c->string = strdup(ud1a->string);
- ud1c->integer = ud1a->integer;
- ud1d->string = strdup(ud1b->string);
- ud1d->integer = ud1b->integer;
-
- ret = g_malloc0(sizeof(UserDefTwo));
- ret->string = strdup("blah1");
- ret->dict.string = strdup("blah2");
- ret->dict.dict.userdef = ud1c;
- ret->dict.dict.string = strdup("blah3");
- ret->dict.has_dict2 = true;
- ret->dict.dict2.userdef = ud1d;
- ret->dict.dict2.string = strdup("blah4");
-
- return ret;
-}
-
-/* test commands with no input and no return value */
-static void test_dispatch_cmd(void)
-{
- QDict *req = qdict_new();
- QObject *resp;
-
- qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
-
- resp = qmp_dispatch(QOBJECT(req));
- assert(resp != NULL);
- assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
-
- qobject_decref(resp);
- QDECREF(req);
-}
-
-/* test commands that return an error due to invalid parameters */
-static void test_dispatch_cmd_error(void)
-{
- QDict *req = qdict_new();
- QObject *resp;
-
- qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
-
- resp = qmp_dispatch(QOBJECT(req));
- assert(resp != NULL);
- assert(qdict_haskey(qobject_to_qdict(resp), "error"));
-
- qobject_decref(resp);
- QDECREF(req);
-}
-
-/* test commands that involve both input parameters and return values */
-static void test_dispatch_cmd_io(void)
-{
- QDict *req = qdict_new();
- QDict *args = qdict_new();
- QDict *ud1a = qdict_new();
- QDict *ud1b = qdict_new();
- QObject *resp;
-
- qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42)));
- qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello")));
- qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422)));
- qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2")));
- qdict_put_obj(args, "ud1a", QOBJECT(ud1a));
- qdict_put_obj(args, "ud1b", QOBJECT(ud1b));
- qdict_put_obj(req, "arguments", QOBJECT(args));
-
- qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
-
- /* TODO: put in full payload and check for errors */
- resp = qmp_dispatch(QOBJECT(req));
- assert(resp != NULL);
- assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
-
- qobject_decref(resp);
- QDECREF(req);
-}
-
-/* test generated dealloc functions for generated types */
-static void test_dealloc_types(void)
-{
- UserDefOne *ud1test, *ud1a, *ud1b;
- UserDefOneList *ud1list;
-
- ud1test = g_malloc0(sizeof(UserDefOne));
- ud1test->integer = 42;
- ud1test->string = g_strdup("hi there 42");
-
- qapi_free_UserDefOne(ud1test);
-
- ud1a = g_malloc0(sizeof(UserDefOne));
- ud1a->integer = 43;
- ud1a->string = g_strdup("hi there 43");
-
- ud1b = g_malloc0(sizeof(UserDefOne));
- ud1b->integer = 44;
- ud1b->string = g_strdup("hi there 44");
-
- ud1list = g_malloc0(sizeof(UserDefOneList));
- ud1list->value = ud1a;
- ud1list->next = g_malloc0(sizeof(UserDefOneList));
- ud1list->next->value = ud1b;
-
- qapi_free_UserDefOneList(ud1list);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
- g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error);
- g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
- g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
-
- module_call_init(MODULE_INIT_QAPI);
- g_test_run();
-
- return 0;
-}
diff --git a/test-qmp-input-strict.c b/test-qmp-input-strict.c
deleted file mode 100644
index f6df8cb..0000000
--- a/test-qmp-input-strict.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * QMP Input Visitor unit-tests (strict mode).
- *
- * Copyright (C) 2011-2012 Red Hat Inc.
- *
- * Authors:
- * Luiz Capitulino <lcapitulino at redhat.com>
- * Paolo Bonzini <pbonzini at redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <glib.h>
-#include <stdarg.h>
-
-#include "qapi/qmp-input-visitor.h"
-#include "test-qapi-types.h"
-#include "test-qapi-visit.h"
-#include "qemu-objects.h"
-
-typedef struct TestInputVisitorData {
- QObject *obj;
- QmpInputVisitor *qiv;
-} TestInputVisitorData;
-
-static void validate_teardown(TestInputVisitorData *data,
- const void *unused)
-{
- qobject_decref(data->obj);
- data->obj = NULL;
-
- if (data->qiv) {
- qmp_input_visitor_cleanup(data->qiv);
- data->qiv = NULL;
- }
-}
-
-/* This is provided instead of a test setup function so that the JSON
- string used by the tests are kept in the test functions (and not
- int main()) */
-static GCC_FMT_ATTR(2, 3)
-Visitor *validate_test_init(TestInputVisitorData *data,
- const char *json_string, ...)
-{
- Visitor *v;
- va_list ap;
-
- va_start(ap, json_string);
- data->obj = qobject_from_jsonv(json_string, &ap);
- va_end(ap);
-
- g_assert(data->obj != NULL);
-
- data->qiv = qmp_input_visitor_new_strict(data->obj);
- g_assert(data->qiv != NULL);
-
- v = qmp_input_get_visitor(data->qiv);
- g_assert(v != NULL);
-
- return v;
-}
-
-typedef struct TestStruct
-{
- int64_t integer;
- bool boolean;
- char *string;
-} TestStruct;
-
-static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
- const char *name, Error **errp)
-{
- visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
- errp);
-
- visit_type_int(v, &(*obj)->integer, "integer", errp);
- visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
- visit_type_str(v, &(*obj)->string, "string", errp);
-
- visit_end_struct(v, errp);
-}
-
-static void test_validate_struct(TestInputVisitorData *data,
- const void *unused)
-{
- TestStruct *p = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
-
- visit_type_TestStruct(v, &p, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_free(p->string);
- g_free(p);
-}
-
-static void test_validate_struct_nested(TestInputVisitorData *data,
- const void *unused)
-{
- UserDefNested *udp = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
-
- visit_type_UserDefNested(v, &udp, NULL, &errp);
- g_assert(!error_is_set(&errp));
- qapi_free_UserDefNested(udp);
-}
-
-static void test_validate_list(TestInputVisitorData *data,
- const void *unused)
-{
- UserDefOneList *head = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
-
- visit_type_UserDefOneList(v, &head, NULL, &errp);
- g_assert(!error_is_set(&errp));
- qapi_free_UserDefOneList(head);
-}
-
-static void test_validate_union(TestInputVisitorData *data,
- const void *unused)
-{
- UserDefUnion *tmp = NULL;
- Visitor *v;
- Error *errp = NULL;
-
- v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
-
- visit_type_UserDefUnion(v, &tmp, NULL, &errp);
- g_assert(!error_is_set(&errp));
- qapi_free_UserDefUnion(tmp);
-}
-
-static void test_validate_fail_struct(TestInputVisitorData *data,
- const void *unused)
-{
- TestStruct *p = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }");
-
- visit_type_TestStruct(v, &p, NULL, &errp);
- g_assert(error_is_set(&errp));
- if (p) {
- g_free(p->string);
- }
- g_free(p);
-}
-
-static void test_validate_fail_struct_nested(TestInputVisitorData *data,
- const void *unused)
-{
- UserDefNested *udp = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}");
-
- visit_type_UserDefNested(v, &udp, NULL, &errp);
- g_assert(error_is_set(&errp));
- qapi_free_UserDefNested(udp);
-}
-
-static void test_validate_fail_list(TestInputVisitorData *data,
- const void *unused)
-{
- UserDefOneList *head = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]");
-
- visit_type_UserDefOneList(v, &head, NULL, &errp);
- g_assert(error_is_set(&errp));
- qapi_free_UserDefOneList(head);
-}
-
-static void test_validate_fail_union(TestInputVisitorData *data,
- const void *unused)
-{
- UserDefUnion *tmp = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 }, 'extra': 'yyy' }");
-
- visit_type_UserDefUnion(v, &tmp, NULL, &errp);
- g_assert(error_is_set(&errp));
- qapi_free_UserDefUnion(tmp);
-}
-
-static void validate_test_add(const char *testpath,
- TestInputVisitorData *data,
- void (*test_func)(TestInputVisitorData *data, const void *user_data))
-{
- g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
- validate_teardown);
-}
-
-int main(int argc, char **argv)
-{
- TestInputVisitorData testdata;
-
- g_test_init(&argc, &argv, NULL);
-
- validate_test_add("/visitor/input-strict/pass/struct",
- &testdata, test_validate_struct);
- validate_test_add("/visitor/input-strict/pass/struct-nested",
- &testdata, test_validate_struct_nested);
- validate_test_add("/visitor/input-strict/pass/list",
- &testdata, test_validate_list);
- validate_test_add("/visitor/input-strict/pass/union",
- &testdata, test_validate_union);
- validate_test_add("/visitor/input-strict/fail/struct",
- &testdata, test_validate_fail_struct);
- validate_test_add("/visitor/input-strict/fail/struct-nested",
- &testdata, test_validate_fail_struct_nested);
- validate_test_add("/visitor/input-strict/fail/list",
- &testdata, test_validate_fail_list);
- validate_test_add("/visitor/input-strict/fail/union",
- &testdata, test_validate_fail_union);
-
- g_test_run();
-
- return 0;
-}
diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
deleted file mode 100644
index c30fdc4..0000000
--- a/test-qmp-input-visitor.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * QMP Input Visitor unit-tests.
- *
- * Copyright (C) 2011 Red Hat Inc.
- *
- * Authors:
- * Luiz Capitulino <lcapitulino at redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <glib.h>
-#include <stdarg.h>
-
-#include "qapi/qmp-input-visitor.h"
-#include "test-qapi-types.h"
-#include "test-qapi-visit.h"
-#include "qemu-objects.h"
-
-typedef struct TestInputVisitorData {
- QObject *obj;
- QmpInputVisitor *qiv;
-} TestInputVisitorData;
-
-static void visitor_input_teardown(TestInputVisitorData *data,
- const void *unused)
-{
- qobject_decref(data->obj);
- data->obj = NULL;
-
- if (data->qiv) {
- qmp_input_visitor_cleanup(data->qiv);
- data->qiv = NULL;
- }
-}
-
-/* This is provided instead of a test setup function so that the JSON
- string used by the tests are kept in the test functions (and not
- int main()) */
-static GCC_FMT_ATTR(2, 3)
-Visitor *visitor_input_test_init(TestInputVisitorData *data,
- const char *json_string, ...)
-{
- Visitor *v;
- va_list ap;
-
- va_start(ap, json_string);
- data->obj = qobject_from_jsonv(json_string, &ap);
- va_end(ap);
-
- g_assert(data->obj != NULL);
-
- data->qiv = qmp_input_visitor_new(data->obj);
- g_assert(data->qiv != NULL);
-
- v = qmp_input_get_visitor(data->qiv);
- g_assert(v != NULL);
-
- return v;
-}
-
-static void test_visitor_in_int(TestInputVisitorData *data,
- const void *unused)
-{
- int64_t res = 0, value = -42;
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, "%" PRId64, value);
-
- visit_type_int(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, value);
-}
-
-static void test_visitor_in_bool(TestInputVisitorData *data,
- const void *unused)
-{
- Error *errp = NULL;
- bool res = false;
- Visitor *v;
-
- v = visitor_input_test_init(data, "true");
-
- visit_type_bool(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, true);
-}
-
-static void test_visitor_in_number(TestInputVisitorData *data,
- const void *unused)
-{
- double res = 0, value = 3.14;
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, "%f", value);
-
- visit_type_number(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpfloat(res, ==, value);
-}
-
-static void test_visitor_in_string(TestInputVisitorData *data,
- const void *unused)
-{
- char *res = NULL, *value = (char *) "Q E M U";
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, "%s", value);
-
- visit_type_str(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpstr(res, ==, value);
-
- g_free(res);
-}
-
-static void test_visitor_in_enum(TestInputVisitorData *data,
- const void *unused)
-{
- Error *errp = NULL;
- Visitor *v;
- EnumOne i;
-
- for (i = 0; EnumOne_lookup[i]; i++) {
- EnumOne res = -1;
-
- v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]);
-
- visit_type_EnumOne(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(i, ==, res);
-
- visitor_input_teardown(data, NULL);
- }
-
- data->obj = NULL;
- data->qiv = NULL;
-}
-
-typedef struct TestStruct
-{
- int64_t integer;
- bool boolean;
- char *string;
-} TestStruct;
-
-static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
- const char *name, Error **errp)
-{
- visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
- errp);
-
- visit_type_int(v, &(*obj)->integer, "integer", errp);
- visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
- visit_type_str(v, &(*obj)->string, "string", errp);
-
- visit_end_struct(v, errp);
-}
-
-static void test_visitor_in_struct(TestInputVisitorData *data,
- const void *unused)
-{
- TestStruct *p = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
-
- visit_type_TestStruct(v, &p, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(p->integer, ==, -42);
- g_assert(p->boolean == true);
- g_assert_cmpstr(p->string, ==, "foo");
-
- g_free(p->string);
- g_free(p);
-}
-
-static void check_and_free_str(char *str, const char *cmp)
-{
- g_assert_cmpstr(str, ==, cmp);
- g_free(str);
-}
-
-static void test_visitor_in_struct_nested(TestInputVisitorData *data,
- const void *unused)
-{
- UserDefNested *udp = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
-
- visit_type_UserDefNested(v, &udp, NULL, &errp);
- g_assert(!error_is_set(&errp));
-
- check_and_free_str(udp->string0, "string0");
- check_and_free_str(udp->dict1.string1, "string1");
- g_assert_cmpint(udp->dict1.dict2.userdef1->integer, ==, 42);
- check_and_free_str(udp->dict1.dict2.userdef1->string, "string");
- check_and_free_str(udp->dict1.dict2.string2, "string2");
- g_assert(udp->dict1.has_dict3 == false);
-
- g_free(udp->dict1.dict2.userdef1);
- g_free(udp);
-}
-
-static void test_visitor_in_list(TestInputVisitorData *data,
- const void *unused)
-{
- UserDefOneList *item, *head = NULL;
- Error *errp = NULL;
- Visitor *v;
- int i;
-
- v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
-
- visit_type_UserDefOneList(v, &head, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert(head != NULL);
-
- for (i = 0, item = head; item; item = item->next, i++) {
- char string[12];
-
- snprintf(string, sizeof(string), "string%d", i);
- g_assert_cmpstr(item->value->string, ==, string);
- g_assert_cmpint(item->value->integer, ==, 42 + i);
- }
-
- qapi_free_UserDefOneList(head);
-}
-
-static void test_visitor_in_union(TestInputVisitorData *data,
- const void *unused)
-{
- Visitor *v;
- Error *err = NULL;
- UserDefUnion *tmp;
-
- v = visitor_input_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
-
- visit_type_UserDefUnion(v, &tmp, NULL, &err);
- g_assert(err == NULL);
- g_assert_cmpint(tmp->kind, ==, USER_DEF_UNION_KIND_B);
- g_assert_cmpint(tmp->b->integer, ==, 42);
- qapi_free_UserDefUnion(tmp);
-}
-
-static void input_visitor_test_add(const char *testpath,
- TestInputVisitorData *data,
- void (*test_func)(TestInputVisitorData *data, const void *user_data))
-{
- g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
- visitor_input_teardown);
-}
-
-static void test_visitor_in_errors(TestInputVisitorData *data,
- const void *unused)
-{
- TestStruct *p = NULL;
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }");
-
- visit_type_TestStruct(v, &p, NULL, &errp);
- g_assert(error_is_set(&errp));
- g_assert(p->string == NULL);
-
- g_free(p->string);
- g_free(p);
-}
-
-int main(int argc, char **argv)
-{
- TestInputVisitorData in_visitor_data;
-
- g_test_init(&argc, &argv, NULL);
-
- input_visitor_test_add("/visitor/input/int",
- &in_visitor_data, test_visitor_in_int);
- input_visitor_test_add("/visitor/input/bool",
- &in_visitor_data, test_visitor_in_bool);
- input_visitor_test_add("/visitor/input/number",
- &in_visitor_data, test_visitor_in_number);
- input_visitor_test_add("/visitor/input/string",
- &in_visitor_data, test_visitor_in_string);
- input_visitor_test_add("/visitor/input/enum",
- &in_visitor_data, test_visitor_in_enum);
- input_visitor_test_add("/visitor/input/struct",
- &in_visitor_data, test_visitor_in_struct);
- input_visitor_test_add("/visitor/input/struct-nested",
- &in_visitor_data, test_visitor_in_struct_nested);
- input_visitor_test_add("/visitor/input/list",
- &in_visitor_data, test_visitor_in_list);
- input_visitor_test_add("/visitor/input/union",
- &in_visitor_data, test_visitor_in_union);
- input_visitor_test_add("/visitor/input/errors",
- &in_visitor_data, test_visitor_in_errors);
-
- g_test_run();
-
- return 0;
-}
diff --git a/test-qmp-output-visitor.c b/test-qmp-output-visitor.c
deleted file mode 100644
index 24a6359..0000000
--- a/test-qmp-output-visitor.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * QMP Output Visitor unit-tests.
- *
- * Copyright (C) 2011 Red Hat Inc.
- *
- * Authors:
- * Luiz Capitulino <lcapitulino at redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <glib.h>
-
-#include "qapi/qmp-output-visitor.h"
-#include "test-qapi-types.h"
-#include "test-qapi-visit.h"
-#include "qemu-objects.h"
-
-typedef struct TestOutputVisitorData {
- QmpOutputVisitor *qov;
- Visitor *ov;
-} TestOutputVisitorData;
-
-static void visitor_output_setup(TestOutputVisitorData *data,
- const void *unused)
-{
- data->qov = qmp_output_visitor_new();
- g_assert(data->qov != NULL);
-
- data->ov = qmp_output_get_visitor(data->qov);
- g_assert(data->ov != NULL);
-}
-
-static void visitor_output_teardown(TestOutputVisitorData *data,
- const void *unused)
-{
- qmp_output_visitor_cleanup(data->qov);
- data->qov = NULL;
- data->ov = NULL;
-}
-
-static void test_visitor_out_int(TestOutputVisitorData *data,
- const void *unused)
-{
- int64_t value = -42;
- Error *errp = NULL;
- QObject *obj;
-
- visit_type_int(data->ov, &value, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QINT);
- g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, value);
-
- qobject_decref(obj);
-}
-
-static void test_visitor_out_bool(TestOutputVisitorData *data,
- const void *unused)
-{
- Error *errp = NULL;
- bool value = true;
- QObject *obj;
-
- visit_type_bool(data->ov, &value, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
- g_assert(qbool_get_int(qobject_to_qbool(obj)) == value);
-
- qobject_decref(obj);
-}
-
-static void test_visitor_out_number(TestOutputVisitorData *data,
- const void *unused)
-{
- double value = 3.14;
- Error *errp = NULL;
- QObject *obj;
-
- visit_type_number(data->ov, &value, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QFLOAT);
- g_assert(qfloat_get_double(qobject_to_qfloat(obj)) == value);
-
- qobject_decref(obj);
-}
-
-static void test_visitor_out_string(TestOutputVisitorData *data,
- const void *unused)
-{
- char *string = (char *) "Q E M U";
- Error *errp = NULL;
- QObject *obj;
-
- visit_type_str(data->ov, &string, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
- g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, string);
-
- qobject_decref(obj);
-}
-
-static void test_visitor_out_no_string(TestOutputVisitorData *data,
- const void *unused)
-{
- char *string = NULL;
- Error *errp = NULL;
- QObject *obj;
-
- /* A null string should return "" */
- visit_type_str(data->ov, &string, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
- g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, "");
-
- qobject_decref(obj);
-}
-
-static void test_visitor_out_enum(TestOutputVisitorData *data,
- const void *unused)
-{
- Error *errp = NULL;
- QObject *obj;
- EnumOne i;
-
- for (i = 0; i < ENUM_ONE_MAX; i++) {
- visit_type_EnumOne(data->ov, &i, "unused", &errp);
- g_assert(!error_is_set(&errp));
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
- g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==,
- EnumOne_lookup[i]);
- qobject_decref(obj);
- }
-}
-
-static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
- const void *unused)
-{
- EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
- Error *errp;
-
- for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
- errp = NULL;
- visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
- g_assert(error_is_set(&errp) == true);
- error_free(errp);
- }
-}
-
-typedef struct TestStruct
-{
- int64_t integer;
- bool boolean;
- char *string;
-} TestStruct;
-
-static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
- const char *name, Error **errp)
-{
- visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
- errp);
-
- visit_type_int(v, &(*obj)->integer, "integer", errp);
- visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
- visit_type_str(v, &(*obj)->string, "string", errp);
-
- visit_end_struct(v, errp);
-}
-
-static void test_visitor_out_struct(TestOutputVisitorData *data,
- const void *unused)
-{
- TestStruct test_struct = { .integer = 42,
- .boolean = false,
- .string = (char *) "foo"};
- TestStruct *p = &test_struct;
- Error *errp = NULL;
- QObject *obj;
- QDict *qdict;
-
- visit_type_TestStruct(data->ov, &p, NULL, &errp);
- g_assert(!error_is_set(&errp));
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QDICT);
-
- qdict = qobject_to_qdict(obj);
- g_assert_cmpint(qdict_size(qdict), ==, 3);
- g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42);
- g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, 0);
- g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "foo");
-
- QDECREF(qdict);
-}
-
-static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
- const void *unused)
-{
- int64_t value = 42;
- Error *errp = NULL;
- UserDefNested *ud2;
- QObject *obj;
- QDict *qdict, *dict1, *dict2, *dict3, *userdef;
- const char *string = "user def string";
- const char *strings[] = { "forty two", "forty three", "forty four",
- "forty five" };
-
- ud2 = g_malloc0(sizeof(*ud2));
- ud2->string0 = g_strdup(strings[0]);
-
- ud2->dict1.string1 = g_strdup(strings[1]);
- ud2->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
- ud2->dict1.dict2.userdef1->string = g_strdup(string);
- ud2->dict1.dict2.userdef1->integer = value;
- ud2->dict1.dict2.string2 = g_strdup(strings[2]);
-
- ud2->dict1.has_dict3 = true;
- ud2->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne));
- ud2->dict1.dict3.userdef2->string = g_strdup(string);
- ud2->dict1.dict3.userdef2->integer = value;
- ud2->dict1.dict3.string3 = g_strdup(strings[3]);
-
- visit_type_UserDefNested(data->ov, &ud2, "unused", &errp);
- g_assert(!error_is_set(&errp));
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QDICT);
-
- qdict = qobject_to_qdict(obj);
- g_assert_cmpint(qdict_size(qdict), ==, 2);
- g_assert_cmpstr(qdict_get_str(qdict, "string0"), ==, strings[0]);
-
- dict1 = qdict_get_qdict(qdict, "dict1");
- g_assert_cmpint(qdict_size(dict1), ==, 3);
- g_assert_cmpstr(qdict_get_str(dict1, "string1"), ==, strings[1]);
-
- dict2 = qdict_get_qdict(dict1, "dict2");
- g_assert_cmpint(qdict_size(dict2), ==, 2);
- g_assert_cmpstr(qdict_get_str(dict2, "string2"), ==, strings[2]);
- userdef = qdict_get_qdict(dict2, "userdef1");
- g_assert_cmpint(qdict_size(userdef), ==, 2);
- g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
- g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
-
- dict3 = qdict_get_qdict(dict1, "dict3");
- g_assert_cmpint(qdict_size(dict3), ==, 2);
- g_assert_cmpstr(qdict_get_str(dict3, "string3"), ==, strings[3]);
- userdef = qdict_get_qdict(dict3, "userdef2");
- g_assert_cmpint(qdict_size(userdef), ==, 2);
- g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
- g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
-
- QDECREF(qdict);
- qapi_free_UserDefNested(ud2);
-}
-
-static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
- const void *unused)
-{
- EnumOne bad_values[] = { ENUM_ONE_MAX, -1 };
- UserDefOne u = { 0 }, *pu = &u;
- Error *errp;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
- errp = NULL;
- u.has_enum1 = true;
- u.enum1 = bad_values[i];
- visit_type_UserDefOne(data->ov, &pu, "unused", &errp);
- g_assert(error_is_set(&errp) == true);
- error_free(errp);
- }
-}
-
-typedef struct TestStructList
-{
- TestStruct *value;
- struct TestStructList *next;
-} TestStructList;
-
-static void visit_type_TestStructList(Visitor *v, TestStructList **obj,
- const char *name, Error **errp)
-{
- GenericList *i, **head = (GenericList **)obj;
-
- visit_start_list(v, name, errp);
-
- for (*head = i = visit_next_list(v, head, errp); i; i = visit_next_list(v, &i, errp)) {
- TestStructList *native_i = (TestStructList *)i;
- visit_type_TestStruct(v, &native_i->value, NULL, errp);
- }
-
- visit_end_list(v, errp);
-}
-
-static void test_visitor_out_list(TestOutputVisitorData *data,
- const void *unused)
-{
- char *value_str = (char *) "list value";
- TestStructList *p, *head = NULL;
- const int max_items = 10;
- bool value_bool = true;
- int value_int = 10;
- Error *errp = NULL;
- QListEntry *entry;
- QObject *obj;
- QList *qlist;
- int i;
-
- for (i = 0; i < max_items; i++) {
- p = g_malloc0(sizeof(*p));
- p->value = g_malloc0(sizeof(*p->value));
- p->value->integer = value_int;
- p->value->boolean = value_bool;
- p->value->string = value_str;
-
- p->next = head;
- head = p;
- }
-
- visit_type_TestStructList(data->ov, &head, NULL, &errp);
- g_assert(!error_is_set(&errp));
-
- obj = qmp_output_get_qobject(data->qov);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
- qlist = qobject_to_qlist(obj);
- g_assert(!qlist_empty(qlist));
-
- i = 0;
- QLIST_FOREACH_ENTRY(qlist, entry) {
- QDict *qdict;
-
- g_assert(qobject_type(entry->value) == QTYPE_QDICT);
- qdict = qobject_to_qdict(entry->value);
- g_assert_cmpint(qdict_size(qdict), ==, 3);
- g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int);
- g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool);
- g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str);
- i++;
- }
- g_assert_cmpint(i, ==, max_items);
-
- QDECREF(qlist);
-
- for (p = head; p;) {
- TestStructList *tmp = p->next;
- g_free(p->value);
- g_free(p);
- p = tmp;
- }
-}
-
-static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
- const void *unused)
-{
- UserDefNestedList *p, *head = NULL;
- const char string[] = "foo bar";
- int i, max_count = 1024;
-
- for (i = 0; i < max_count; i++) {
- p = g_malloc0(sizeof(*p));
- p->value = g_malloc0(sizeof(*p->value));
-
- p->value->string0 = g_strdup(string);
- p->value->dict1.string1 = g_strdup(string);
- p->value->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
- p->value->dict1.dict2.userdef1->string = g_strdup(string);
- p->value->dict1.dict2.userdef1->integer = 42;
- p->value->dict1.dict2.string2 = g_strdup(string);
- p->value->dict1.has_dict3 = false;
-
- p->next = head;
- head = p;
- }
-
- qapi_free_UserDefNestedList(head);
-}
-
-static void test_visitor_out_union(TestOutputVisitorData *data,
- const void *unused)
-{
- QObject *arg, *qvalue;
- QDict *qdict, *value;
-
- Error *err = NULL;
-
- UserDefUnion *tmp = g_malloc0(sizeof(UserDefUnion));
- tmp->kind = USER_DEF_UNION_KIND_A;
- tmp->a = g_malloc0(sizeof(UserDefA));
- tmp->a->boolean = true;
-
- visit_type_UserDefUnion(data->ov, &tmp, NULL, &err);
- g_assert(err == NULL);
- arg = qmp_output_get_qobject(data->qov);
-
- g_assert(qobject_type(arg) == QTYPE_QDICT);
- qdict = qobject_to_qdict(arg);
-
- g_assert_cmpstr(qdict_get_str(qdict, "type"), ==, "a");
-
- qvalue = qdict_get(qdict, "data");
- g_assert(data != NULL);
- g_assert(qobject_type(qvalue) == QTYPE_QDICT);
- value = qobject_to_qdict(qvalue);
- g_assert_cmpint(qdict_get_bool(value, "boolean"), ==, true);
-
- qapi_free_UserDefUnion(tmp);
- QDECREF(qdict);
-}
-
-static void output_visitor_test_add(const char *testpath,
- TestOutputVisitorData *data,
- void (*test_func)(TestOutputVisitorData *data, const void *user_data))
-{
- g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
- test_func, visitor_output_teardown);
-}
-
-int main(int argc, char **argv)
-{
- TestOutputVisitorData out_visitor_data;
-
- g_test_init(&argc, &argv, NULL);
-
- output_visitor_test_add("/visitor/output/int",
- &out_visitor_data, test_visitor_out_int);
- output_visitor_test_add("/visitor/output/bool",
- &out_visitor_data, test_visitor_out_bool);
- output_visitor_test_add("/visitor/output/number",
- &out_visitor_data, test_visitor_out_number);
- output_visitor_test_add("/visitor/output/string",
- &out_visitor_data, test_visitor_out_string);
- output_visitor_test_add("/visitor/output/no-string",
- &out_visitor_data, test_visitor_out_no_string);
- output_visitor_test_add("/visitor/output/enum",
- &out_visitor_data, test_visitor_out_enum);
- output_visitor_test_add("/visitor/output/enum-errors",
- &out_visitor_data, test_visitor_out_enum_errors);
- output_visitor_test_add("/visitor/output/struct",
- &out_visitor_data, test_visitor_out_struct);
- output_visitor_test_add("/visitor/output/struct-nested",
- &out_visitor_data, test_visitor_out_struct_nested);
- output_visitor_test_add("/visitor/output/struct-errors",
- &out_visitor_data, test_visitor_out_struct_errors);
- output_visitor_test_add("/visitor/output/list",
- &out_visitor_data, test_visitor_out_list);
- output_visitor_test_add("/visitor/output/list-qapi-free",
- &out_visitor_data, test_visitor_out_list_qapi_free);
- output_visitor_test_add("/visitor/output/union",
- &out_visitor_data, test_visitor_out_union);
-
- g_test_run();
-
- return 0;
-}
diff --git a/test-string-input-visitor.c b/test-string-input-visitor.c
deleted file mode 100644
index 5370e32..0000000
--- a/test-string-input-visitor.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * String Input Visitor unit-tests.
- *
- * Copyright (C) 2012 Red Hat Inc.
- *
- * Authors:
- * Paolo Bonzini <pbonzini at redhat.com> (based on test-qmp-input-visitor)
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <glib.h>
-#include <stdarg.h>
-
-#include "qapi/string-input-visitor.h"
-#include "test-qapi-types.h"
-#include "test-qapi-visit.h"
-#include "qemu-objects.h"
-
-typedef struct TestInputVisitorData {
- StringInputVisitor *siv;
-} TestInputVisitorData;
-
-static void visitor_input_teardown(TestInputVisitorData *data,
- const void *unused)
-{
- if (data->siv) {
- string_input_visitor_cleanup(data->siv);
- data->siv = NULL;
- }
-}
-
-/* This is provided instead of a test setup function so that the JSON
- string used by the tests are kept in the test functions (and not
- int main()) */
-static
-Visitor *visitor_input_test_init(TestInputVisitorData *data,
- const char *string)
-{
- Visitor *v;
-
- data->siv = string_input_visitor_new(string);
- g_assert(data->siv != NULL);
-
- v = string_input_get_visitor(data->siv);
- g_assert(v != NULL);
-
- return v;
-}
-
-static void test_visitor_in_int(TestInputVisitorData *data,
- const void *unused)
-{
- int64_t res = 0, value = -42;
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, "-42");
-
- visit_type_int(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, value);
-}
-
-static void test_visitor_in_bool(TestInputVisitorData *data,
- const void *unused)
-{
- Error *errp = NULL;
- bool res = false;
- Visitor *v;
-
- v = visitor_input_test_init(data, "true");
-
- visit_type_bool(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, true);
- visitor_input_teardown(data, unused);
-
- v = visitor_input_test_init(data, "yes");
-
- visit_type_bool(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, true);
- visitor_input_teardown(data, unused);
-
- v = visitor_input_test_init(data, "on");
-
- visit_type_bool(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, true);
- visitor_input_teardown(data, unused);
-
- v = visitor_input_test_init(data, "false");
-
- visit_type_bool(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, false);
- visitor_input_teardown(data, unused);
-
- v = visitor_input_test_init(data, "no");
-
- visit_type_bool(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, false);
- visitor_input_teardown(data, unused);
-
- v = visitor_input_test_init(data, "off");
-
- visit_type_bool(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(res, ==, false);
-}
-
-static void test_visitor_in_number(TestInputVisitorData *data,
- const void *unused)
-{
- double res = 0, value = 3.14;
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, "3.14");
-
- visit_type_number(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpfloat(res, ==, value);
-}
-
-static void test_visitor_in_string(TestInputVisitorData *data,
- const void *unused)
-{
- char *res = NULL, *value = (char *) "Q E M U";
- Error *errp = NULL;
- Visitor *v;
-
- v = visitor_input_test_init(data, value);
-
- visit_type_str(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpstr(res, ==, value);
-
- g_free(res);
-}
-
-static void test_visitor_in_enum(TestInputVisitorData *data,
- const void *unused)
-{
- Error *errp = NULL;
- Visitor *v;
- EnumOne i;
-
- for (i = 0; EnumOne_lookup[i]; i++) {
- EnumOne res = -1;
-
- v = visitor_input_test_init(data, EnumOne_lookup[i]);
-
- visit_type_EnumOne(v, &res, NULL, &errp);
- g_assert(!error_is_set(&errp));
- g_assert_cmpint(i, ==, res);
-
- visitor_input_teardown(data, NULL);
- }
-
- data->siv = NULL;
-}
-
-static void input_visitor_test_add(const char *testpath,
- TestInputVisitorData *data,
- void (*test_func)(TestInputVisitorData *data, const void *user_data))
-{
- g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
- visitor_input_teardown);
-}
-
-int main(int argc, char **argv)
-{
- TestInputVisitorData in_visitor_data;
-
- g_test_init(&argc, &argv, NULL);
-
- input_visitor_test_add("/string-visitor/input/int",
- &in_visitor_data, test_visitor_in_int);
- input_visitor_test_add("/string-visitor/input/bool",
- &in_visitor_data, test_visitor_in_bool);
- input_visitor_test_add("/string-visitor/input/number",
- &in_visitor_data, test_visitor_in_number);
- input_visitor_test_add("/string-visitor/input/string",
- &in_visitor_data, test_visitor_in_string);
- input_visitor_test_add("/string-visitor/input/enum",
- &in_visitor_data, test_visitor_in_enum);
-
- g_test_run();
-
- return 0;
-}
diff --git a/test-string-output-visitor.c b/test-string-output-visitor.c
deleted file mode 100644
index 22909b8..0000000
--- a/test-string-output-visitor.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * String Output Visitor unit-tests.
- *
- * Copyright (C) 2012 Red Hat Inc.
- *
- * Authors:
- * Paolo Bonzini <pbonzini at redhat.com> (based on test-qmp-output-visitor)
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <glib.h>
-
-#include "qapi/string-output-visitor.h"
-#include "test-qapi-types.h"
-#include "test-qapi-visit.h"
-#include "qemu-objects.h"
-
-typedef struct TestOutputVisitorData {
- StringOutputVisitor *sov;
- Visitor *ov;
-} TestOutputVisitorData;
-
-static void visitor_output_setup(TestOutputVisitorData *data,
- const void *unused)
-{
- data->sov = string_output_visitor_new();
- g_assert(data->sov != NULL);
-
- data->ov = string_output_get_visitor(data->sov);
- g_assert(data->ov != NULL);
-}
-
-static void visitor_output_teardown(TestOutputVisitorData *data,
- const void *unused)
-{
- string_output_visitor_cleanup(data->sov);
- data->sov = NULL;
- data->ov = NULL;
-}
-
-static void test_visitor_out_int(TestOutputVisitorData *data,
- const void *unused)
-{
- int64_t value = -42;
- Error *errp = NULL;
- char *str;
-
- visit_type_int(data->ov, &value, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- str = string_output_get_string(data->sov);
- g_assert(str != NULL);
- g_assert_cmpstr(str, ==, "-42");
- g_free(str);
-}
-
-static void test_visitor_out_bool(TestOutputVisitorData *data,
- const void *unused)
-{
- Error *errp = NULL;
- bool value = true;
- char *str;
-
- visit_type_bool(data->ov, &value, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- str = string_output_get_string(data->sov);
- g_assert(str != NULL);
- g_assert_cmpstr(str, ==, "true");
- g_free(str);
-}
-
-static void test_visitor_out_number(TestOutputVisitorData *data,
- const void *unused)
-{
- double value = 3.14;
- Error *errp = NULL;
- char *str;
-
- visit_type_number(data->ov, &value, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- str = string_output_get_string(data->sov);
- g_assert(str != NULL);
- g_assert_cmpstr(str, ==, "3.14");
- g_free(str);
-}
-
-static void test_visitor_out_string(TestOutputVisitorData *data,
- const void *unused)
-{
- char *string = (char *) "Q E M U";
- Error *errp = NULL;
- char *str;
-
- visit_type_str(data->ov, &string, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- str = string_output_get_string(data->sov);
- g_assert(str != NULL);
- g_assert_cmpstr(str, ==, string);
- g_free(str);
-}
-
-static void test_visitor_out_no_string(TestOutputVisitorData *data,
- const void *unused)
-{
- char *string = NULL;
- Error *errp = NULL;
- char *str;
-
- /* A null string should return "" */
- visit_type_str(data->ov, &string, NULL, &errp);
- g_assert(error_is_set(&errp) == 0);
-
- str = string_output_get_string(data->sov);
- g_assert(str != NULL);
- g_assert_cmpstr(str, ==, "");
- g_free(str);
-}
-
-static void test_visitor_out_enum(TestOutputVisitorData *data,
- const void *unused)
-{
- Error *errp = NULL;
- char *str;
- EnumOne i;
-
- for (i = 0; i < ENUM_ONE_MAX; i++) {
- visit_type_EnumOne(data->ov, &i, "unused", &errp);
- g_assert(!error_is_set(&errp));
-
- str = string_output_get_string(data->sov);
- g_assert(str != NULL);
- g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
- g_free(str);
- }
-}
-
-static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
- const void *unused)
-{
- EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
- Error *errp;
-
- for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
- errp = NULL;
- visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
- g_assert(error_is_set(&errp) == true);
- error_free(errp);
- }
-}
-
-static void output_visitor_test_add(const char *testpath,
- TestOutputVisitorData *data,
- void (*test_func)(TestOutputVisitorData *data, const void *user_data))
-{
- g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
- test_func, visitor_output_teardown);
-}
-
-int main(int argc, char **argv)
-{
- TestOutputVisitorData out_visitor_data;
-
- g_test_init(&argc, &argv, NULL);
-
- output_visitor_test_add("/string-visitor/output/int",
- &out_visitor_data, test_visitor_out_int);
- output_visitor_test_add("/string-visitor/output/bool",
- &out_visitor_data, test_visitor_out_bool);
- output_visitor_test_add("/string-visitor/output/number",
- &out_visitor_data, test_visitor_out_number);
- output_visitor_test_add("/string-visitor/output/string",
- &out_visitor_data, test_visitor_out_string);
- output_visitor_test_add("/string-visitor/output/no-string",
- &out_visitor_data, test_visitor_out_no_string);
- output_visitor_test_add("/string-visitor/output/enum",
- &out_visitor_data, test_visitor_out_enum);
- output_visitor_test_add("/string-visitor/output/enum-errors",
- &out_visitor_data, test_visitor_out_enum_errors);
-
- g_test_run();
-
- return 0;
-}
diff --git a/tests/Makefile b/tests/Makefile
index 2a2fff7..17f6ece 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,61 +1,113 @@
export SRC_PATH
-CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist
-CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor
-CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine
-CHECKS += test-qmp-commands
-CHECKS += $(SRC_PATH)/tests/qemu-iotests-quick.sh
-
-check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
-
-check-qint: check-qint.o qint.o $(tools-obj-y)
-check-qstring: check-qstring.o qstring.o $(tools-obj-y)
-check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y)
-check-qlist: check-qlist.o qlist.o qint.o $(tools-obj-y)
-check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y)
-check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
-test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
-
-test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-input-strict.o \
-test-string-input-visitor.o test-string-output-visitor.o \
- test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
-
-$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
+check-unit-y = tests/check-qdict$(EXESUF)
+check-unit-y += tests/check-qfloat$(EXESUF)
+check-unit-y += tests/check-qint$(EXESUF)
+check-unit-y += tests/check-qstring$(EXESUF)
+check-unit-y += tests/check-qlist$(EXESUF)
+check-unit-y += tests/check-qjson$(EXESUF)
+check-unit-y += tests/test-qmp-output-visitor$(EXESUF)
+check-unit-y += tests/test-qmp-input-visitor$(EXESUF)
+check-unit-y += tests/test-qmp-input-strict$(EXESUF)
+check-unit-y += tests/test-qmp-commands$(EXESUF)
+check-unit-y += tests/test-string-input-visitor$(EXESUF)
+check-unit-y += tests/test-string-output-visitor$(EXESUF)
+check-unit-y += tests/test-coroutine$(EXESUF)
+
+check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
+
+GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
+
+test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
+ tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.o \
+ tests/test-coroutine.o tests/test-string-output-visitor.o \
+ tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
+ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
+ tests/test-qmp-commands.o
+
+test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
+test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
+test-qapi-obj-y += module.o
+
+$(test-obj-y): $(GENERATED_HEADERS)
+$(test-obj-y): QEMU_INCLUDES += -Itests
+
+tests/check-qint$(EXESUF): tests/check-qint.o qint.o $(tools-obj-y)
+tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o $(tools-obj-y)
+tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y)
+tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o $(tools-obj-y)
+tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o $(tools-obj-y)
+tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) $(tools-obj-y)
+tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y)
+
+tests/test-qapi-types.c tests/test-qapi-types.h :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
-$(qapi-dir)/test-qapi-visit.c $(qapi-dir)/test-qapi-visit.h :\
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
+tests/test-qapi-visit.c tests/test-qapi-visit.h :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
-$(qapi-dir)/test-qmp-commands.h $(qapi-dir)/test-qmp-marshal.c :\
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
+tests/test-qmp-commands.h tests/test-qmp-marshal.c :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
-test-string-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-string-output-visitor: test-string-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
+tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
+tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y)
+tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y)
+tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
+tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
-test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+.PHONY: check-help
+check-help:
+ @echo "Regression testing targets:"
+ @echo
+ @echo " make check Run all tests"
+ @echo " make check-unit Run qobject tests"
+ @echo " make check-block Run block tests"
+ @echo " make check-report.html Generates an HTML test report"
+ @echo
+ @echo "Please note that HTML reports do not regenerate if the unit tests"
+ @echo "has not changed."
+ @echo
+ @echo "The variable SPEED can be set to control the gtester speed setting."
+ @echo "Default options are -k and (for make V=1) --verbose; they can be"
+ @echo "changed with variable GTESTER_OPTIONS."
-test-qmp-input-strict.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-qmp-input-strict: test-qmp-input-strict.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+.SECONDARY:
-test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+SPEED = quick
+GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
-test-qmp-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-qmp-input-visitor: test-qmp-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+# gtester tests, possibly with verbose output
-test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
-test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
+.PHONY: $(patsubst %, check-%, $(check-unit-y))
+$(patsubst %, check-%, $(check-unit-y)): check-%: %
+ $(call quiet-command,gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
-$(SRC_PATH)/tests/qemu-iotests-quick.sh: qemu-img qemu-io
+# gtester tests with XML output
+check-report-unit.xml: $(check-unit-y)
+ $(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^, "GTESTER $@")
-.PHONY: check check-block
+# Reports and overall runs
-check: $(CHECKS)
- $(call quiet-command, gtester $(CHECKS), " CHECK")
+check-report.xml: check-report-unit.xml
+ $(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, " GEN $@")
-check-block:
- $(call quiet-command, $(SHELL) $(SRC_PATH)/tests/check-block.sh , " CHECK")
+check-report.html: check-report.xml
+ $(call quiet-command,gtester-report $< > $@, " GEN $@")
+
+
+# Other tests
+
+.PHONY: check-tests/qemu-iotests-quick.sh
+check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF)
+ $<
+
+# Consolidated targets
+
+.PHONY: check-unit check
+check-unit: $(patsubst %,check-%, $(check-unit-y))
+check-block: $(patsubst %,check-%, $(check-block-y))
+check: check-unit
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
new file mode 100644
index 0000000..fc0d276
--- /dev/null
+++ b/tests/check-qdict.c
@@ -0,0 +1,378 @@
+/*
+ * QDict unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include <glib.h>
+
+#include "qint.h"
+#include "qdict.h"
+#include "qstring.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+static void qdict_new_test(void)
+{
+ QDict *qdict;
+
+ qdict = qdict_new();
+ g_assert(qdict != NULL);
+ g_assert(qdict_size(qdict) == 0);
+ g_assert(qdict->base.refcnt == 1);
+ g_assert(qobject_type(QOBJECT(qdict)) == QTYPE_QDICT);
+
+ // destroy doesn't exit yet
+ g_free(qdict);
+}
+
+static void qdict_put_obj_test(void)
+{
+ QInt *qi;
+ QDict *qdict;
+ QDictEntry *ent;
+ const int num = 42;
+
+ qdict = qdict_new();
+
+ // key "" will have tdb hash 12345
+ qdict_put_obj(qdict, "", QOBJECT(qint_from_int(num)));
+
+ g_assert(qdict_size(qdict) == 1);
+ ent = QLIST_FIRST(&qdict->table[12345 % QDICT_BUCKET_MAX]);
+ qi = qobject_to_qint(ent->value);
+ g_assert(qint_get_int(qi) == num);
+
+ // destroy doesn't exit yet
+ QDECREF(qi);
+ g_free(ent->key);
+ g_free(ent);
+ g_free(qdict);
+}
+
+static void qdict_destroy_simple_test(void)
+{
+ QDict *qdict;
+
+ qdict = qdict_new();
+ qdict_put_obj(qdict, "num", QOBJECT(qint_from_int(0)));
+ qdict_put_obj(qdict, "str", QOBJECT(qstring_from_str("foo")));
+
+ QDECREF(qdict);
+}
+
+static void qdict_get_test(void)
+{
+ QInt *qi;
+ QObject *obj;
+ const int value = -42;
+ const char *key = "test";
+ QDict *tests_dict = qdict_new();
+
+ qdict_put(tests_dict, key, qint_from_int(value));
+
+ obj = qdict_get(tests_dict, key);
+ g_assert(obj != NULL);
+
+ qi = qobject_to_qint(obj);
+ g_assert(qint_get_int(qi) == value);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_get_int_test(void)
+{
+ int ret;
+ const int value = 100;
+ const char *key = "int";
+ QDict *tests_dict = qdict_new();
+
+ qdict_put(tests_dict, key, qint_from_int(value));
+
+ ret = qdict_get_int(tests_dict, key);
+ g_assert(ret == value);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_get_try_int_test(void)
+{
+ int ret;
+ const int value = 100;
+ const char *key = "int";
+ QDict *tests_dict = qdict_new();
+
+ qdict_put(tests_dict, key, qint_from_int(value));
+
+ ret = qdict_get_try_int(tests_dict, key, 0);
+ g_assert(ret == value);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_get_str_test(void)
+{
+ const char *p;
+ const char *key = "key";
+ const char *str = "string";
+ QDict *tests_dict = qdict_new();
+
+ qdict_put(tests_dict, key, qstring_from_str(str));
+
+ p = qdict_get_str(tests_dict, key);
+ g_assert(p != NULL);
+ g_assert(strcmp(p, str) == 0);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_get_try_str_test(void)
+{
+ const char *p;
+ const char *key = "key";
+ const char *str = "string";
+ QDict *tests_dict = qdict_new();
+
+ qdict_put(tests_dict, key, qstring_from_str(str));
+
+ p = qdict_get_try_str(tests_dict, key);
+ g_assert(p != NULL);
+ g_assert(strcmp(p, str) == 0);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_haskey_not_test(void)
+{
+ QDict *tests_dict = qdict_new();
+ g_assert(qdict_haskey(tests_dict, "test") == 0);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_haskey_test(void)
+{
+ const char *key = "test";
+ QDict *tests_dict = qdict_new();
+
+ qdict_put(tests_dict, key, qint_from_int(0));
+ g_assert(qdict_haskey(tests_dict, key) == 1);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_del_test(void)
+{
+ const char *key = "key test";
+ QDict *tests_dict = qdict_new();
+
+ qdict_put(tests_dict, key, qstring_from_str("foo"));
+ g_assert(qdict_size(tests_dict) == 1);
+
+ qdict_del(tests_dict, key);
+
+ g_assert(qdict_size(tests_dict) == 0);
+ g_assert(qdict_haskey(tests_dict, key) == 0);
+
+ QDECREF(tests_dict);
+}
+
+static void qobject_to_qdict_test(void)
+{
+ QDict *tests_dict = qdict_new();
+ g_assert(qobject_to_qdict(QOBJECT(tests_dict)) == tests_dict);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_iterapi_test(void)
+{
+ int count;
+ const QDictEntry *ent;
+ QDict *tests_dict = qdict_new();
+
+ g_assert(qdict_first(tests_dict) == NULL);
+
+ qdict_put(tests_dict, "key1", qint_from_int(1));
+ qdict_put(tests_dict, "key2", qint_from_int(2));
+ qdict_put(tests_dict, "key3", qint_from_int(3));
+
+ count = 0;
+ for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
+ g_assert(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
+ count++;
+ }
+
+ g_assert(count == qdict_size(tests_dict));
+
+ /* Do it again to test restarting */
+ count = 0;
+ for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
+ g_assert(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
+ count++;
+ }
+
+ g_assert(count == qdict_size(tests_dict));
+
+ QDECREF(tests_dict);
+}
+
+/*
+ * Errors test-cases
+ */
+
+static void qdict_put_exists_test(void)
+{
+ int value;
+ const char *key = "exists";
+ QDict *tests_dict = qdict_new();
+
+ qdict_put(tests_dict, key, qint_from_int(1));
+ qdict_put(tests_dict, key, qint_from_int(2));
+
+ value = qdict_get_int(tests_dict, key);
+ g_assert(value == 2);
+
+ g_assert(qdict_size(tests_dict) == 1);
+
+ QDECREF(tests_dict);
+}
+
+static void qdict_get_not_exists_test(void)
+{
+ QDict *tests_dict = qdict_new();
+ g_assert(qdict_get(tests_dict, "foo") == NULL);
+
+ QDECREF(tests_dict);
+}
+
+/*
+ * Stress test-case
+ *
+ * This is a lot big for a unit-test, but there is no other place
+ * to have it.
+ */
+
+static void remove_dots(char *string)
+{
+ char *p = strchr(string, ':');
+ if (p)
+ *p = '\0';
+}
+
+static QString *read_line(FILE *file, char *key)
+{
+ char value[128];
+
+ if (fscanf(file, "%127s%127s", key, value) == EOF) {
+ return NULL;
+ }
+ remove_dots(key);
+ return qstring_from_str(value);
+}
+
+#define reset_file(file) fseek(file, 0L, SEEK_SET)
+
+static void qdict_stress_test(void)
+{
+ size_t lines;
+ char key[128];
+ FILE *test_file;
+ QDict *qdict;
+ QString *value;
+ const char *test_file_path = "qdict-test-data.txt";
+
+ test_file = fopen(test_file_path, "r");
+ g_assert(test_file != NULL);
+
+ // Create the dict
+ qdict = qdict_new();
+ g_assert(qdict != NULL);
+
+ // Add everything from the test file
+ for (lines = 0;; lines++) {
+ value = read_line(test_file, key);
+ if (!value)
+ break;
+
+ qdict_put(qdict, key, value);
+ }
+ g_assert(qdict_size(qdict) == lines);
+
+ // Check if everything is really in there
+ reset_file(test_file);
+ for (;;) {
+ const char *str1, *str2;
+
+ value = read_line(test_file, key);
+ if (!value)
+ break;
+
+ str1 = qstring_get_str(value);
+
+ str2 = qdict_get_str(qdict, key);
+ g_assert(str2 != NULL);
+
+ g_assert(strcmp(str1, str2) == 0);
+
+ QDECREF(value);
+ }
+
+ // Delete everything
+ reset_file(test_file);
+ for (;;) {
+ value = read_line(test_file, key);
+ if (!value)
+ break;
+
+ qdict_del(qdict, key);
+ QDECREF(value);
+
+ g_assert(qdict_haskey(qdict, key) == 0);
+ }
+ fclose(test_file);
+
+ g_assert(qdict_size(qdict) == 0);
+ QDECREF(qdict);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/public/new", qdict_new_test);
+ g_test_add_func("/public/put_obj", qdict_put_obj_test);
+ g_test_add_func("/public/destroy_simple", qdict_destroy_simple_test);
+
+ /* Continue, but now with fixtures */
+ g_test_add_func("/public/get", qdict_get_test);
+ g_test_add_func("/public/get_int", qdict_get_int_test);
+ g_test_add_func("/public/get_try_int", qdict_get_try_int_test);
+ g_test_add_func("/public/get_str", qdict_get_str_test);
+ g_test_add_func("/public/get_try_str", qdict_get_try_str_test);
+ g_test_add_func("/public/haskey_not", qdict_haskey_not_test);
+ g_test_add_func("/public/haskey", qdict_haskey_test);
+ g_test_add_func("/public/del", qdict_del_test);
+ g_test_add_func("/public/to_qdict", qobject_to_qdict_test);
+ g_test_add_func("/public/iterapi", qdict_iterapi_test);
+
+ g_test_add_func("/errors/put_exists", qdict_put_exists_test);
+ g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
+
+ /* The Big one */
+ if (g_test_slow()) {
+ g_test_add_func("/stress/test", qdict_stress_test);
+ }
+
+ return g_test_run();
+}
diff --git a/tests/check-qfloat.c b/tests/check-qfloat.c
new file mode 100644
index 0000000..cdc66ea
--- /dev/null
+++ b/tests/check-qfloat.c
@@ -0,0 +1,53 @@
+/*
+ * QFloat unit-tests.
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#include <glib.h>
+
+#include "qfloat.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+static void qfloat_from_double_test(void)
+{
+ QFloat *qf;
+ const double value = -42.23423;
+
+ qf = qfloat_from_double(value);
+ g_assert(qf != NULL);
+ g_assert(qf->value == value);
+ g_assert(qf->base.refcnt == 1);
+ g_assert(qobject_type(QOBJECT(qf)) == QTYPE_QFLOAT);
+
+ // destroy doesn't exit yet
+ g_free(qf);
+}
+
+static void qfloat_destroy_test(void)
+{
+ QFloat *qf = qfloat_from_double(0.0);
+ QDECREF(qf);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/public/from_double", qfloat_from_double_test);
+ g_test_add_func("/public/destroy", qfloat_destroy_test);
+
+ return g_test_run();
+}
diff --git a/tests/check-qint.c b/tests/check-qint.c
new file mode 100644
index 0000000..5a27119
--- /dev/null
+++ b/tests/check-qint.c
@@ -0,0 +1,87 @@
+/*
+ * QInt unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include <glib.h>
+
+#include "qint.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+static void qint_from_int_test(void)
+{
+ QInt *qi;
+ const int value = -42;
+
+ qi = qint_from_int(value);
+ g_assert(qi != NULL);
+ g_assert(qi->value == value);
+ g_assert(qi->base.refcnt == 1);
+ g_assert(qobject_type(QOBJECT(qi)) == QTYPE_QINT);
+
+ // destroy doesn't exit yet
+ g_free(qi);
+}
+
+static void qint_destroy_test(void)
+{
+ QInt *qi = qint_from_int(0);
+ QDECREF(qi);
+}
+
+static void qint_from_int64_test(void)
+{
+ QInt *qi;
+ const int64_t value = 0x1234567890abcdefLL;
+
+ qi = qint_from_int(value);
+ g_assert((int64_t) qi->value == value);
+
+ QDECREF(qi);
+}
+
+static void qint_get_int_test(void)
+{
+ QInt *qi;
+ const int value = 123456;
+
+ qi = qint_from_int(value);
+ g_assert(qint_get_int(qi) == value);
+
+ QDECREF(qi);
+}
+
+static void qobject_to_qint_test(void)
+{
+ QInt *qi;
+
+ qi = qint_from_int(0);
+ g_assert(qobject_to_qint(QOBJECT(qi)) == qi);
+
+ QDECREF(qi);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/public/from_int", qint_from_int_test);
+ g_test_add_func("/public/destroy", qint_destroy_test);
+ g_test_add_func("/public/from_int64", qint_from_int64_test);
+ g_test_add_func("/public/get_int", qint_get_int_test);
+ g_test_add_func("/public/to_qint", qobject_to_qint_test);
+
+ return g_test_run();
+}
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
new file mode 100644
index 0000000..526e25e
--- /dev/null
+++ b/tests/check-qjson.c
@@ -0,0 +1,728 @@
+/*
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#include <glib.h>
+
+#include "qstring.h"
+#include "qint.h"
+#include "qdict.h"
+#include "qlist.h"
+#include "qfloat.h"
+#include "qbool.h"
+#include "qjson.h"
+
+#include "qemu-common.h"
+
+static void escaped_string(void)
+{
+ int i;
+ struct {
+ const char *encoded;
+ const char *decoded;
+ int skip;
+ } test_cases[] = {
+ { "\"\\b\"", "\b" },
+ { "\"\\f\"", "\f" },
+ { "\"\\n\"", "\n" },
+ { "\"\\r\"", "\r" },
+ { "\"\\t\"", "\t" },
+ { "\"/\"", "/" },
+ { "\"\\/\"", "/", .skip = 1 },
+ { "\"\\\\\"", "\\" },
+ { "\"\\\"\"", "\"" },
+ { "\"hello world \\\"embedded string\\\"\"",
+ "hello world \"embedded string\"" },
+ { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
+ { "\"single byte utf-8 \\u0020\"", "single byte utf-8 ", .skip = 1 },
+ { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
+ { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
+ {}
+ };
+
+ for (i = 0; test_cases[i].encoded; i++) {
+ QObject *obj;
+ QString *str;
+
+ obj = qobject_from_json(test_cases[i].encoded);
+
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+
+ str = qobject_to_qstring(obj);
+ g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].decoded);
+
+ if (test_cases[i].skip == 0) {
+ str = qobject_to_json(obj);
+ g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].encoded);
+ qobject_decref(obj);
+ }
+
+ QDECREF(str);
+ }
+}
+
+static void simple_string(void)
+{
+ int i;
+ struct {
+ const char *encoded;
+ const char *decoded;
+ } test_cases[] = {
+ { "\"hello world\"", "hello world" },
+ { "\"the quick brown fox jumped over the fence\"",
+ "the quick brown fox jumped over the fence" },
+ {}
+ };
+
+ for (i = 0; test_cases[i].encoded; i++) {
+ QObject *obj;
+ QString *str;
+
+ obj = qobject_from_json(test_cases[i].encoded);
+
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+
+ str = qobject_to_qstring(obj);
+ g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+ str = qobject_to_json(obj);
+ g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
+
+ qobject_decref(obj);
+
+ QDECREF(str);
+ }
+}
+
+static void single_quote_string(void)
+{
+ int i;
+ struct {
+ const char *encoded;
+ const char *decoded;
+ } test_cases[] = {
+ { "'hello world'", "hello world" },
+ { "'the quick brown fox \\' jumped over the fence'",
+ "the quick brown fox ' jumped over the fence" },
+ {}
+ };
+
+ for (i = 0; test_cases[i].encoded; i++) {
+ QObject *obj;
+ QString *str;
+
+ obj = qobject_from_json(test_cases[i].encoded);
+
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+
+ str = qobject_to_qstring(obj);
+ g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+ QDECREF(str);
+ }
+}
+
+static void vararg_string(void)
+{
+ int i;
+ struct {
+ const char *decoded;
+ } test_cases[] = {
+ { "hello world" },
+ { "the quick brown fox jumped over the fence" },
+ {}
+ };
+
+ for (i = 0; test_cases[i].decoded; i++) {
+ QObject *obj;
+ QString *str;
+
+ obj = qobject_from_jsonf("%s", test_cases[i].decoded);
+
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+
+ str = qobject_to_qstring(obj);
+ g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+
+ QDECREF(str);
+ }
+}
+
+static void simple_number(void)
+{
+ int i;
+ struct {
+ const char *encoded;
+ int64_t decoded;
+ int skip;
+ } test_cases[] = {
+ { "0", 0 },
+ { "1234", 1234 },
+ { "1", 1 },
+ { "-32", -32 },
+ { "-0", 0, .skip = 1 },
+ { },
+ };
+
+ for (i = 0; test_cases[i].encoded; i++) {
+ QObject *obj;
+ QInt *qint;
+
+ obj = qobject_from_json(test_cases[i].encoded);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QINT);
+
+ qint = qobject_to_qint(obj);
+ g_assert(qint_get_int(qint) == test_cases[i].decoded);
+ if (test_cases[i].skip == 0) {
+ QString *str;
+
+ str = qobject_to_json(obj);
+ g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
+ QDECREF(str);
+ }
+
+ QDECREF(qint);
+ }
+}
+
+static void float_number(void)
+{
+ int i;
+ struct {
+ const char *encoded;
+ double decoded;
+ int skip;
+ } test_cases[] = {
+ { "32.43", 32.43 },
+ { "0.222", 0.222 },
+ { "-32.12313", -32.12313 },
+ { "-32.20e-10", -32.20e-10, .skip = 1 },
+ { },
+ };
+
+ for (i = 0; test_cases[i].encoded; i++) {
+ QObject *obj;
+ QFloat *qfloat;
+
+ obj = qobject_from_json(test_cases[i].encoded);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QFLOAT);
+
+ qfloat = qobject_to_qfloat(obj);
+ g_assert(qfloat_get_double(qfloat) == test_cases[i].decoded);
+
+ if (test_cases[i].skip == 0) {
+ QString *str;
+
+ str = qobject_to_json(obj);
+ g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
+ QDECREF(str);
+ }
+
+ QDECREF(qfloat);
+ }
+}
+
+static void vararg_number(void)
+{
+ QObject *obj;
+ QInt *qint;
+ QFloat *qfloat;
+ int value = 0x2342;
+ int64_t value64 = 0x2342342343LL;
+ double valuef = 2.323423423;
+
+ obj = qobject_from_jsonf("%d", value);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QINT);
+
+ qint = qobject_to_qint(obj);
+ g_assert(qint_get_int(qint) == value);
+
+ QDECREF(qint);
+
+ obj = qobject_from_jsonf("%" PRId64, value64);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QINT);
+
+ qint = qobject_to_qint(obj);
+ g_assert(qint_get_int(qint) == value64);
+
+ QDECREF(qint);
+
+ obj = qobject_from_jsonf("%f", valuef);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QFLOAT);
+
+ qfloat = qobject_to_qfloat(obj);
+ g_assert(qfloat_get_double(qfloat) == valuef);
+
+ QDECREF(qfloat);
+}
+
+static void keyword_literal(void)
+{
+ QObject *obj;
+ QBool *qbool;
+ QString *str;
+
+ obj = qobject_from_json("true");
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QBOOL);
+
+ qbool = qobject_to_qbool(obj);
+ g_assert(qbool_get_int(qbool) != 0);
+
+ str = qobject_to_json(obj);
+ g_assert(strcmp(qstring_get_str(str), "true") == 0);
+ QDECREF(str);
+
+ QDECREF(qbool);
+
+ obj = qobject_from_json("false");
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QBOOL);
+
+ qbool = qobject_to_qbool(obj);
+ g_assert(qbool_get_int(qbool) == 0);
+
+ str = qobject_to_json(obj);
+ g_assert(strcmp(qstring_get_str(str), "false") == 0);
+ QDECREF(str);
+
+ QDECREF(qbool);
+
+ obj = qobject_from_jsonf("%i", false);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QBOOL);
+
+ qbool = qobject_to_qbool(obj);
+ g_assert(qbool_get_int(qbool) == 0);
+
+ QDECREF(qbool);
+
+ obj = qobject_from_jsonf("%i", true);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QBOOL);
+
+ qbool = qobject_to_qbool(obj);
+ g_assert(qbool_get_int(qbool) != 0);
+
+ QDECREF(qbool);
+}
+
+typedef struct LiteralQDictEntry LiteralQDictEntry;
+typedef struct LiteralQObject LiteralQObject;
+
+struct LiteralQObject
+{
+ int type;
+ union {
+ int64_t qint;
+ const char *qstr;
+ LiteralQDictEntry *qdict;
+ LiteralQObject *qlist;
+ } value;
+};
+
+struct LiteralQDictEntry
+{
+ const char *key;
+ LiteralQObject value;
+};
+
+#define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
+#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
+#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
+#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
+
+typedef struct QListCompareHelper
+{
+ int index;
+ LiteralQObject *objs;
+ int result;
+} QListCompareHelper;
+
+static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
+
+static void compare_helper(QObject *obj, void *opaque)
+{
+ QListCompareHelper *helper = opaque;
+
+ if (helper->result == 0) {
+ return;
+ }
+
+ if (helper->objs[helper->index].type == QTYPE_NONE) {
+ helper->result = 0;
+ return;
+ }
+
+ helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
+}
+
+static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
+{
+ if (lhs->type != qobject_type(rhs)) {
+ return 0;
+ }
+
+ switch (lhs->type) {
+ case QTYPE_QINT:
+ return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
+ case QTYPE_QSTRING:
+ return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
+ case QTYPE_QDICT: {
+ int i;
+
+ for (i = 0; lhs->value.qdict[i].key; i++) {
+ QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
+
+ if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+ case QTYPE_QLIST: {
+ QListCompareHelper helper;
+
+ helper.index = 0;
+ helper.objs = lhs->value.qlist;
+ helper.result = 1;
+
+ qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
+
+ return helper.result;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void simple_dict(void)
+{
+ int i;
+ struct {
+ const char *encoded;
+ LiteralQObject decoded;
+ } test_cases[] = {
+ {
+ .encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
+ .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+ { "foo", QLIT_QINT(42) },
+ { "bar", QLIT_QSTR("hello world") },
+ { }
+ })),
+ }, {
+ .encoded = "{}",
+ .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+ { }
+ })),
+ }, {
+ .encoded = "{\"foo\": 43}",
+ .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+ { "foo", QLIT_QINT(43) },
+ { }
+ })),
+ },
+ { }
+ };
+
+ for (i = 0; test_cases[i].encoded; i++) {
+ QObject *obj;
+ QString *str;
+
+ obj = qobject_from_json(test_cases[i].encoded);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QDICT);
+
+ g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+ str = qobject_to_json(obj);
+ qobject_decref(obj);
+
+ obj = qobject_from_json(qstring_get_str(str));
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QDICT);
+
+ g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+ qobject_decref(obj);
+ QDECREF(str);
+ }
+}
+
+static void simple_list(void)
+{
+ int i;
+ struct {
+ const char *encoded;
+ LiteralQObject decoded;
+ } test_cases[] = {
+ {
+ .encoded = "[43,42]",
+ .decoded = QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QINT(43),
+ QLIT_QINT(42),
+ { }
+ })),
+ },
+ {
+ .encoded = "[43]",
+ .decoded = QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QINT(43),
+ { }
+ })),
+ },
+ {
+ .encoded = "[]",
+ .decoded = QLIT_QLIST(((LiteralQObject[]){
+ { }
+ })),
+ },
+ {
+ .encoded = "[{}]",
+ .decoded = QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QDICT(((LiteralQDictEntry[]){
+ {},
+ })),
+ {},
+ })),
+ },
+ { }
+ };
+
+ for (i = 0; test_cases[i].encoded; i++) {
+ QObject *obj;
+ QString *str;
+
+ obj = qobject_from_json(test_cases[i].encoded);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QLIST);
+
+ g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+ str = qobject_to_json(obj);
+ qobject_decref(obj);
+
+ obj = qobject_from_json(qstring_get_str(str));
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QLIST);
+
+ g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+ qobject_decref(obj);
+ QDECREF(str);
+ }
+}
+
+static void simple_whitespace(void)
+{
+ int i;
+ struct {
+ const char *encoded;
+ LiteralQObject decoded;
+ } test_cases[] = {
+ {
+ .encoded = " [ 43 , 42 ]",
+ .decoded = QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QINT(43),
+ QLIT_QINT(42),
+ { }
+ })),
+ },
+ {
+ .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
+ .decoded = QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QINT(43),
+ QLIT_QDICT(((LiteralQDictEntry[]){
+ { "h", QLIT_QSTR("b") },
+ { }})),
+ QLIT_QLIST(((LiteralQObject[]){
+ { }})),
+ QLIT_QINT(42),
+ { }
+ })),
+ },
+ {
+ .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
+ .decoded = QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QINT(43),
+ QLIT_QDICT(((LiteralQDictEntry[]){
+ { "h", QLIT_QSTR("b") },
+ { "a", QLIT_QINT(32) },
+ { }})),
+ QLIT_QLIST(((LiteralQObject[]){
+ { }})),
+ QLIT_QINT(42),
+ { }
+ })),
+ },
+ { }
+ };
+
+ for (i = 0; test_cases[i].encoded; i++) {
+ QObject *obj;
+ QString *str;
+
+ obj = qobject_from_json(test_cases[i].encoded);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QLIST);
+
+ g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+ str = qobject_to_json(obj);
+ qobject_decref(obj);
+
+ obj = qobject_from_json(qstring_get_str(str));
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QLIST);
+
+ g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+
+ qobject_decref(obj);
+ QDECREF(str);
+ }
+}
+
+static void simple_varargs(void)
+{
+ QObject *embedded_obj;
+ QObject *obj;
+ LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QINT(1),
+ QLIT_QINT(2),
+ QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QINT(32),
+ QLIT_QINT(42),
+ {}})),
+ {}}));
+
+ embedded_obj = qobject_from_json("[32, 42]");
+ g_assert(embedded_obj != NULL);
+
+ obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
+ g_assert(obj != NULL);
+
+ g_assert(compare_litqobj_to_qobj(&decoded, obj) == 1);
+
+ qobject_decref(obj);
+}
+
+static void empty_input(void)
+{
+ const char *empty = "";
+
+ QObject *obj = qobject_from_json(empty);
+ g_assert(obj == NULL);
+}
+
+static void unterminated_string(void)
+{
+ QObject *obj = qobject_from_json("\"abc");
+ g_assert(obj == NULL);
+}
+
+static void unterminated_sq_string(void)
+{
+ QObject *obj = qobject_from_json("'abc");
+ g_assert(obj == NULL);
+}
+
+static void unterminated_escape(void)
+{
+ QObject *obj = qobject_from_json("\"abc\\\"");
+ g_assert(obj == NULL);
+}
+
+static void unterminated_array(void)
+{
+ QObject *obj = qobject_from_json("[32");
+ g_assert(obj == NULL);
+}
+
+static void unterminated_array_comma(void)
+{
+ QObject *obj = qobject_from_json("[32,");
+ g_assert(obj == NULL);
+}
+
+static void invalid_array_comma(void)
+{
+ QObject *obj = qobject_from_json("[32,}");
+ g_assert(obj == NULL);
+}
+
+static void unterminated_dict(void)
+{
+ QObject *obj = qobject_from_json("{'abc':32");
+ g_assert(obj == NULL);
+}
+
+static void unterminated_dict_comma(void)
+{
+ QObject *obj = qobject_from_json("{'abc':32,");
+ g_assert(obj == NULL);
+}
+
+static void invalid_dict_comma(void)
+{
+ QObject *obj = qobject_from_json("{'abc':32,}");
+ g_assert(obj == NULL);
+}
+
+static void unterminated_literal(void)
+{
+ QObject *obj = qobject_from_json("nul");
+ g_assert(obj == NULL);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/literals/string/simple", simple_string);
+ g_test_add_func("/literals/string/escaped", escaped_string);
+ g_test_add_func("/literals/string/single_quote", single_quote_string);
+ g_test_add_func("/literals/string/vararg", vararg_string);
+
+ g_test_add_func("/literals/number/simple", simple_number);
+ g_test_add_func("/literals/number/float", float_number);
+ g_test_add_func("/literals/number/vararg", vararg_number);
+
+ g_test_add_func("/literals/keyword", keyword_literal);
+
+ g_test_add_func("/dicts/simple_dict", simple_dict);
+ g_test_add_func("/lists/simple_list", simple_list);
+
+ g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
+
+ g_test_add_func("/varargs/simple_varargs", simple_varargs);
+
+ g_test_add_func("/errors/empty_input", empty_input);
+ g_test_add_func("/errors/unterminated/string", unterminated_string);
+ g_test_add_func("/errors/unterminated/escape", unterminated_escape);
+ g_test_add_func("/errors/unterminated/sq_string", unterminated_sq_string);
+ g_test_add_func("/errors/unterminated/array", unterminated_array);
+ g_test_add_func("/errors/unterminated/array_comma", unterminated_array_comma);
+ g_test_add_func("/errors/unterminated/dict", unterminated_dict);
+ g_test_add_func("/errors/unterminated/dict_comma", unterminated_dict_comma);
+ g_test_add_func("/errors/invalid_array_comma", invalid_array_comma);
+ g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma);
+ g_test_add_func("/errors/unterminated/literal", unterminated_literal);
+
+ return g_test_run();
+}
diff --git a/tests/check-qlist.c b/tests/check-qlist.c
new file mode 100644
index 0000000..501ba26
--- /dev/null
+++ b/tests/check-qlist.c
@@ -0,0 +1,127 @@
+/*
+ * QList unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include <glib.h>
+
+#include "qint.h"
+#include "qlist.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+static void qlist_new_test(void)
+{
+ QList *qlist;
+
+ qlist = qlist_new();
+ g_assert(qlist != NULL);
+ g_assert(qlist->base.refcnt == 1);
+ g_assert(qobject_type(QOBJECT(qlist)) == QTYPE_QLIST);
+
+ // destroy doesn't exist yet
+ g_free(qlist);
+}
+
+static void qlist_append_test(void)
+{
+ QInt *qi;
+ QList *qlist;
+ QListEntry *entry;
+
+ qi = qint_from_int(42);
+
+ qlist = qlist_new();
+ qlist_append(qlist, qi);
+
+ entry = QTAILQ_FIRST(&qlist->head);
+ g_assert(entry != NULL);
+ g_assert(entry->value == QOBJECT(qi));
+
+ // destroy doesn't exist yet
+ QDECREF(qi);
+ g_free(entry);
+ g_free(qlist);
+}
+
+static void qobject_to_qlist_test(void)
+{
+ QList *qlist;
+
+ qlist = qlist_new();
+
+ g_assert(qobject_to_qlist(QOBJECT(qlist)) == qlist);
+
+ // destroy doesn't exist yet
+ g_free(qlist);
+}
+
+static void qlist_destroy_test(void)
+{
+ int i;
+ QList *qlist;
+
+ qlist = qlist_new();
+
+ for (i = 0; i < 42; i++)
+ qlist_append(qlist, qint_from_int(i));
+
+ QDECREF(qlist);
+}
+
+static int iter_called;
+static const int iter_max = 42;
+
+static void iter_func(QObject *obj, void *opaque)
+{
+ QInt *qi;
+
+ g_assert(opaque == NULL);
+
+ qi = qobject_to_qint(obj);
+ g_assert(qi != NULL);
+ g_assert((qint_get_int(qi) >= 0) && (qint_get_int(qi) <= iter_max));
+
+ iter_called++;
+}
+
+static void qlist_iter_test(void)
+{
+ int i;
+ QList *qlist;
+
+ qlist = qlist_new();
+
+ for (i = 0; i < iter_max; i++)
+ qlist_append(qlist, qint_from_int(i));
+
+ iter_called = 0;
+ qlist_iter(qlist, iter_func, NULL);
+
+ g_assert(iter_called == iter_max);
+
+ QDECREF(qlist);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/public/new", qlist_new_test);
+ g_test_add_func("/public/append", qlist_append_test);
+ g_test_add_func("/public/to_qlist", qobject_to_qlist_test);
+ g_test_add_func("/public/destroy", qlist_destroy_test);
+ g_test_add_func("/public/iter", qlist_iter_test);
+
+ return g_test_run();
+}
diff --git a/tests/check-qstring.c b/tests/check-qstring.c
new file mode 100644
index 0000000..addad6c
--- /dev/null
+++ b/tests/check-qstring.c
@@ -0,0 +1,107 @@
+/*
+ * QString unit-tests.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include <glib.h>
+
+#include "qstring.h"
+#include "qemu-common.h"
+
+/*
+ * Public Interface test-cases
+ *
+ * (with some violations to access 'private' data)
+ */
+
+static void qstring_from_str_test(void)
+{
+ QString *qstring;
+ const char *str = "QEMU";
+
+ qstring = qstring_from_str(str);
+ g_assert(qstring != NULL);
+ g_assert(qstring->base.refcnt == 1);
+ g_assert(strcmp(str, qstring->string) == 0);
+ g_assert(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
+
+ // destroy doesn't exit yet
+ g_free(qstring->string);
+ g_free(qstring);
+}
+
+static void qstring_destroy_test(void)
+{
+ QString *qstring = qstring_from_str("destroy test");
+ QDECREF(qstring);
+}
+
+static void qstring_get_str_test(void)
+{
+ QString *qstring;
+ const char *ret_str;
+ const char *str = "QEMU/KVM";
+
+ qstring = qstring_from_str(str);
+ ret_str = qstring_get_str(qstring);
+ g_assert(strcmp(ret_str, str) == 0);
+
+ QDECREF(qstring);
+}
+
+static void qstring_append_chr_test(void)
+{
+ int i;
+ QString *qstring;
+ const char *str = "qstring append char unit-test";
+
+ qstring = qstring_new();
+
+ for (i = 0; str[i]; i++)
+ qstring_append_chr(qstring, str[i]);
+
+ g_assert(strcmp(str, qstring_get_str(qstring)) == 0);
+ QDECREF(qstring);
+}
+
+static void qstring_from_substr_test(void)
+{
+ QString *qs;
+
+ qs = qstring_from_substr("virtualization", 3, 9);
+ g_assert(qs != NULL);
+ g_assert(strcmp(qstring_get_str(qs), "tualiza") == 0);
+
+ QDECREF(qs);
+}
+
+
+static void qobject_to_qstring_test(void)
+{
+ QString *qstring;
+
+ qstring = qstring_from_str("foo");
+ g_assert(qobject_to_qstring(QOBJECT(qstring)) == qstring);
+
+ QDECREF(qstring);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/public/from_str", qstring_from_str_test);
+ g_test_add_func("/public/destroy", qstring_destroy_test);
+ g_test_add_func("/public/get_str", qstring_get_str_test);
+ g_test_add_func("/public/append_chr", qstring_append_chr_test);
+ g_test_add_func("/public/from_substr", qstring_from_substr_test);
+ g_test_add_func("/public/to_qstring", qobject_to_qstring_test);
+
+ return g_test_run();
+}
diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c
new file mode 100644
index 0000000..e5d14eb
--- /dev/null
+++ b/tests/test-coroutine.c
@@ -0,0 +1,219 @@
+/*
+ * Coroutine tests
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <glib.h>
+#include "qemu-coroutine.h"
+
+/*
+ * Check that qemu_in_coroutine() works
+ */
+
+static void coroutine_fn verify_in_coroutine(void *opaque)
+{
+ g_assert(qemu_in_coroutine());
+}
+
+static void test_in_coroutine(void)
+{
+ Coroutine *coroutine;
+
+ g_assert(!qemu_in_coroutine());
+
+ coroutine = qemu_coroutine_create(verify_in_coroutine);
+ qemu_coroutine_enter(coroutine, NULL);
+}
+
+/*
+ * Check that qemu_coroutine_self() works
+ */
+
+static void coroutine_fn verify_self(void *opaque)
+{
+ g_assert(qemu_coroutine_self() == opaque);
+}
+
+static void test_self(void)
+{
+ Coroutine *coroutine;
+
+ coroutine = qemu_coroutine_create(verify_self);
+ qemu_coroutine_enter(coroutine, coroutine);
+}
+
+/*
+ * Check that coroutines may nest multiple levels
+ */
+
+typedef struct {
+ unsigned int n_enter; /* num coroutines entered */
+ unsigned int n_return; /* num coroutines returned */
+ unsigned int max; /* maximum level of nesting */
+} NestData;
+
+static void coroutine_fn nest(void *opaque)
+{
+ NestData *nd = opaque;
+
+ nd->n_enter++;
+
+ if (nd->n_enter < nd->max) {
+ Coroutine *child;
+
+ child = qemu_coroutine_create(nest);
+ qemu_coroutine_enter(child, nd);
+ }
+
+ nd->n_return++;
+}
+
+static void test_nesting(void)
+{
+ Coroutine *root;
+ NestData nd = {
+ .n_enter = 0,
+ .n_return = 0,
+ .max = 128,
+ };
+
+ root = qemu_coroutine_create(nest);
+ qemu_coroutine_enter(root, &nd);
+
+ /* Must enter and return from max nesting level */
+ g_assert_cmpint(nd.n_enter, ==, nd.max);
+ g_assert_cmpint(nd.n_return, ==, nd.max);
+}
+
+/*
+ * Check that yield/enter transfer control correctly
+ */
+
+static void coroutine_fn yield_5_times(void *opaque)
+{
+ bool *done = opaque;
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ qemu_coroutine_yield();
+ }
+ *done = true;
+}
+
+static void test_yield(void)
+{
+ Coroutine *coroutine;
+ bool done = false;
+ int i = -1; /* one extra time to return from coroutine */
+
+ coroutine = qemu_coroutine_create(yield_5_times);
+ while (!done) {
+ qemu_coroutine_enter(coroutine, &done);
+ i++;
+ }
+ g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
+}
+
+/*
+ * Check that creation, enter, and return work
+ */
+
+static void coroutine_fn set_and_exit(void *opaque)
+{
+ bool *done = opaque;
+
+ *done = true;
+}
+
+static void test_lifecycle(void)
+{
+ Coroutine *coroutine;
+ bool done = false;
+
+ /* Create, enter, and return from coroutine */
+ coroutine = qemu_coroutine_create(set_and_exit);
+ qemu_coroutine_enter(coroutine, &done);
+ g_assert(done); /* expect done to be true (first time) */
+
+ /* Repeat to check that no state affects this test */
+ done = false;
+ coroutine = qemu_coroutine_create(set_and_exit);
+ qemu_coroutine_enter(coroutine, &done);
+ g_assert(done); /* expect done to be true (second time) */
+}
+
+/*
+ * Lifecycle benchmark
+ */
+
+static void coroutine_fn empty_coroutine(void *opaque)
+{
+ /* Do nothing */
+}
+
+static void perf_lifecycle(void)
+{
+ Coroutine *coroutine;
+ unsigned int i, max;
+ double duration;
+
+ max = 1000000;
+
+ g_test_timer_start();
+ for (i = 0; i < max; i++) {
+ coroutine = qemu_coroutine_create(empty_coroutine);
+ qemu_coroutine_enter(coroutine, NULL);
+ }
+ duration = g_test_timer_elapsed();
+
+ g_test_message("Lifecycle %u iterations: %f s\n", max, duration);
+}
+
+static void perf_nesting(void)
+{
+ unsigned int i, maxcycles, maxnesting;
+ double duration;
+
+ maxcycles = 100000000;
+ maxnesting = 20000;
+ Coroutine *root;
+ NestData nd = {
+ .n_enter = 0,
+ .n_return = 0,
+ .max = maxnesting,
+ };
+
+ g_test_timer_start();
+ for (i = 0; i < maxcycles; i++) {
+ root = qemu_coroutine_create(nest);
+ qemu_coroutine_enter(root, &nd);
+ }
+ duration = g_test_timer_elapsed();
+
+ g_test_message("Nesting %u iterations of %u depth each: %f s\n",
+ maxcycles, maxnesting, duration);
+}
+
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/basic/lifecycle", test_lifecycle);
+ g_test_add_func("/basic/yield", test_yield);
+ g_test_add_func("/basic/nesting", test_nesting);
+ g_test_add_func("/basic/self", test_self);
+ g_test_add_func("/basic/in_coroutine", test_in_coroutine);
+ if (g_test_perf()) {
+ g_test_add_func("/perf/lifecycle", perf_lifecycle);
+ g_test_add_func("/perf/nesting", perf_nesting);
+ }
+ return g_test_run();
+}
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
new file mode 100644
index 0000000..60cbf01
--- /dev/null
+++ b/tests/test-qmp-commands.c
@@ -0,0 +1,139 @@
+#include <glib.h>
+#include "qemu-objects.h"
+#include "test-qmp-commands.h"
+#include "qapi/qmp-core.h"
+#include "module.h"
+
+void qmp_user_def_cmd(Error **errp)
+{
+}
+
+void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
+{
+}
+
+UserDefTwo * qmp_user_def_cmd2(UserDefOne * ud1a, UserDefOne * ud1b, Error **errp)
+{
+ UserDefTwo *ret;
+ UserDefOne *ud1c = g_malloc0(sizeof(UserDefOne));
+ UserDefOne *ud1d = g_malloc0(sizeof(UserDefOne));
+
+ ud1c->string = strdup(ud1a->string);
+ ud1c->integer = ud1a->integer;
+ ud1d->string = strdup(ud1b->string);
+ ud1d->integer = ud1b->integer;
+
+ ret = g_malloc0(sizeof(UserDefTwo));
+ ret->string = strdup("blah1");
+ ret->dict.string = strdup("blah2");
+ ret->dict.dict.userdef = ud1c;
+ ret->dict.dict.string = strdup("blah3");
+ ret->dict.has_dict2 = true;
+ ret->dict.dict2.userdef = ud1d;
+ ret->dict.dict2.string = strdup("blah4");
+
+ return ret;
+}
+
+/* test commands with no input and no return value */
+static void test_dispatch_cmd(void)
+{
+ QDict *req = qdict_new();
+ QObject *resp;
+
+ qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
+
+ resp = qmp_dispatch(QOBJECT(req));
+ assert(resp != NULL);
+ assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+
+ qobject_decref(resp);
+ QDECREF(req);
+}
+
+/* test commands that return an error due to invalid parameters */
+static void test_dispatch_cmd_error(void)
+{
+ QDict *req = qdict_new();
+ QObject *resp;
+
+ qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+ resp = qmp_dispatch(QOBJECT(req));
+ assert(resp != NULL);
+ assert(qdict_haskey(qobject_to_qdict(resp), "error"));
+
+ qobject_decref(resp);
+ QDECREF(req);
+}
+
+/* test commands that involve both input parameters and return values */
+static void test_dispatch_cmd_io(void)
+{
+ QDict *req = qdict_new();
+ QDict *args = qdict_new();
+ QDict *ud1a = qdict_new();
+ QDict *ud1b = qdict_new();
+ QObject *resp;
+
+ qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42)));
+ qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello")));
+ qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422)));
+ qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2")));
+ qdict_put_obj(args, "ud1a", QOBJECT(ud1a));
+ qdict_put_obj(args, "ud1b", QOBJECT(ud1b));
+ qdict_put_obj(req, "arguments", QOBJECT(args));
+
+ qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+ /* TODO: put in full payload and check for errors */
+ resp = qmp_dispatch(QOBJECT(req));
+ assert(resp != NULL);
+ assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+
+ qobject_decref(resp);
+ QDECREF(req);
+}
+
+/* test generated dealloc functions for generated types */
+static void test_dealloc_types(void)
+{
+ UserDefOne *ud1test, *ud1a, *ud1b;
+ UserDefOneList *ud1list;
+
+ ud1test = g_malloc0(sizeof(UserDefOne));
+ ud1test->integer = 42;
+ ud1test->string = g_strdup("hi there 42");
+
+ qapi_free_UserDefOne(ud1test);
+
+ ud1a = g_malloc0(sizeof(UserDefOne));
+ ud1a->integer = 43;
+ ud1a->string = g_strdup("hi there 43");
+
+ ud1b = g_malloc0(sizeof(UserDefOne));
+ ud1b->integer = 44;
+ ud1b->string = g_strdup("hi there 44");
+
+ ud1list = g_malloc0(sizeof(UserDefOneList));
+ ud1list->value = ud1a;
+ ud1list->next = g_malloc0(sizeof(UserDefOneList));
+ ud1list->next->value = ud1b;
+
+ qapi_free_UserDefOneList(ud1list);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
+ g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error);
+ g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
+ g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
+
+ module_call_init(MODULE_INIT_QAPI);
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
new file mode 100644
index 0000000..f6df8cb
--- /dev/null
+++ b/tests/test-qmp-input-strict.c
@@ -0,0 +1,234 @@
+/*
+ * QMP Input Visitor unit-tests (strict mode).
+ *
+ * Copyright (C) 2011-2012 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino at redhat.com>
+ * Paolo Bonzini <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <stdarg.h>
+
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestInputVisitorData {
+ QObject *obj;
+ QmpInputVisitor *qiv;
+} TestInputVisitorData;
+
+static void validate_teardown(TestInputVisitorData *data,
+ const void *unused)
+{
+ qobject_decref(data->obj);
+ data->obj = NULL;
+
+ if (data->qiv) {
+ qmp_input_visitor_cleanup(data->qiv);
+ data->qiv = NULL;
+ }
+}
+
+/* This is provided instead of a test setup function so that the JSON
+ string used by the tests are kept in the test functions (and not
+ int main()) */
+static GCC_FMT_ATTR(2, 3)
+Visitor *validate_test_init(TestInputVisitorData *data,
+ const char *json_string, ...)
+{
+ Visitor *v;
+ va_list ap;
+
+ va_start(ap, json_string);
+ data->obj = qobject_from_jsonv(json_string, &ap);
+ va_end(ap);
+
+ g_assert(data->obj != NULL);
+
+ data->qiv = qmp_input_visitor_new_strict(data->obj);
+ g_assert(data->qiv != NULL);
+
+ v = qmp_input_get_visitor(data->qiv);
+ g_assert(v != NULL);
+
+ return v;
+}
+
+typedef struct TestStruct
+{
+ int64_t integer;
+ bool boolean;
+ char *string;
+} TestStruct;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
+ const char *name, Error **errp)
+{
+ visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
+ errp);
+
+ visit_type_int(v, &(*obj)->integer, "integer", errp);
+ visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+ visit_type_str(v, &(*obj)->string, "string", errp);
+
+ visit_end_struct(v, errp);
+}
+
+static void test_validate_struct(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_free(p->string);
+ g_free(p);
+}
+
+static void test_validate_struct_nested(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNested *udp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
+
+ visit_type_UserDefNested(v, &udp, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefNested(udp);
+}
+
+static void test_validate_list(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *head = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
+
+ visit_type_UserDefOneList(v, &head, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefOneList(head);
+}
+
+static void test_validate_union(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefUnion *tmp = NULL;
+ Visitor *v;
+ Error *errp = NULL;
+
+ v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
+
+ visit_type_UserDefUnion(v, &tmp, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefUnion(tmp);
+}
+
+static void test_validate_fail_struct(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ if (p) {
+ g_free(p->string);
+ }
+ g_free(p);
+}
+
+static void test_validate_fail_struct_nested(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNested *udp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}");
+
+ visit_type_UserDefNested(v, &udp, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefNested(udp);
+}
+
+static void test_validate_fail_list(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *head = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]");
+
+ visit_type_UserDefOneList(v, &head, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefOneList(head);
+}
+
+static void test_validate_fail_union(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefUnion *tmp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 }, 'extra': 'yyy' }");
+
+ visit_type_UserDefUnion(v, &tmp, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefUnion(tmp);
+}
+
+static void validate_test_add(const char *testpath,
+ TestInputVisitorData *data,
+ void (*test_func)(TestInputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
+ validate_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ TestInputVisitorData testdata;
+
+ g_test_init(&argc, &argv, NULL);
+
+ validate_test_add("/visitor/input-strict/pass/struct",
+ &testdata, test_validate_struct);
+ validate_test_add("/visitor/input-strict/pass/struct-nested",
+ &testdata, test_validate_struct_nested);
+ validate_test_add("/visitor/input-strict/pass/list",
+ &testdata, test_validate_list);
+ validate_test_add("/visitor/input-strict/pass/union",
+ &testdata, test_validate_union);
+ validate_test_add("/visitor/input-strict/fail/struct",
+ &testdata, test_validate_fail_struct);
+ validate_test_add("/visitor/input-strict/fail/struct-nested",
+ &testdata, test_validate_fail_struct_nested);
+ validate_test_add("/visitor/input-strict/fail/list",
+ &testdata, test_validate_fail_list);
+ validate_test_add("/visitor/input-strict/fail/union",
+ &testdata, test_validate_fail_union);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
new file mode 100644
index 0000000..c30fdc4
--- /dev/null
+++ b/tests/test-qmp-input-visitor.c
@@ -0,0 +1,308 @@
+/*
+ * QMP Input Visitor unit-tests.
+ *
+ * Copyright (C) 2011 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <stdarg.h>
+
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestInputVisitorData {
+ QObject *obj;
+ QmpInputVisitor *qiv;
+} TestInputVisitorData;
+
+static void visitor_input_teardown(TestInputVisitorData *data,
+ const void *unused)
+{
+ qobject_decref(data->obj);
+ data->obj = NULL;
+
+ if (data->qiv) {
+ qmp_input_visitor_cleanup(data->qiv);
+ data->qiv = NULL;
+ }
+}
+
+/* This is provided instead of a test setup function so that the JSON
+ string used by the tests are kept in the test functions (and not
+ int main()) */
+static GCC_FMT_ATTR(2, 3)
+Visitor *visitor_input_test_init(TestInputVisitorData *data,
+ const char *json_string, ...)
+{
+ Visitor *v;
+ va_list ap;
+
+ va_start(ap, json_string);
+ data->obj = qobject_from_jsonv(json_string, &ap);
+ va_end(ap);
+
+ g_assert(data->obj != NULL);
+
+ data->qiv = qmp_input_visitor_new(data->obj);
+ g_assert(data->qiv != NULL);
+
+ v = qmp_input_get_visitor(data->qiv);
+ g_assert(v != NULL);
+
+ return v;
+}
+
+static void test_visitor_in_int(TestInputVisitorData *data,
+ const void *unused)
+{
+ int64_t res = 0, value = -42;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "%" PRId64, value);
+
+ visit_type_int(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, value);
+}
+
+static void test_visitor_in_bool(TestInputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ bool res = false;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "true");
+
+ visit_type_bool(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, true);
+}
+
+static void test_visitor_in_number(TestInputVisitorData *data,
+ const void *unused)
+{
+ double res = 0, value = 3.14;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "%f", value);
+
+ visit_type_number(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpfloat(res, ==, value);
+}
+
+static void test_visitor_in_string(TestInputVisitorData *data,
+ const void *unused)
+{
+ char *res = NULL, *value = (char *) "Q E M U";
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "%s", value);
+
+ visit_type_str(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpstr(res, ==, value);
+
+ g_free(res);
+}
+
+static void test_visitor_in_enum(TestInputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ Visitor *v;
+ EnumOne i;
+
+ for (i = 0; EnumOne_lookup[i]; i++) {
+ EnumOne res = -1;
+
+ v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]);
+
+ visit_type_EnumOne(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(i, ==, res);
+
+ visitor_input_teardown(data, NULL);
+ }
+
+ data->obj = NULL;
+ data->qiv = NULL;
+}
+
+typedef struct TestStruct
+{
+ int64_t integer;
+ bool boolean;
+ char *string;
+} TestStruct;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
+ const char *name, Error **errp)
+{
+ visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
+ errp);
+
+ visit_type_int(v, &(*obj)->integer, "integer", errp);
+ visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+ visit_type_str(v, &(*obj)->string, "string", errp);
+
+ visit_end_struct(v, errp);
+}
+
+static void test_visitor_in_struct(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(p->integer, ==, -42);
+ g_assert(p->boolean == true);
+ g_assert_cmpstr(p->string, ==, "foo");
+
+ g_free(p->string);
+ g_free(p);
+}
+
+static void check_and_free_str(char *str, const char *cmp)
+{
+ g_assert_cmpstr(str, ==, cmp);
+ g_free(str);
+}
+
+static void test_visitor_in_struct_nested(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNested *udp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
+
+ visit_type_UserDefNested(v, &udp, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+
+ check_and_free_str(udp->string0, "string0");
+ check_and_free_str(udp->dict1.string1, "string1");
+ g_assert_cmpint(udp->dict1.dict2.userdef1->integer, ==, 42);
+ check_and_free_str(udp->dict1.dict2.userdef1->string, "string");
+ check_and_free_str(udp->dict1.dict2.string2, "string2");
+ g_assert(udp->dict1.has_dict3 == false);
+
+ g_free(udp->dict1.dict2.userdef1);
+ g_free(udp);
+}
+
+static void test_visitor_in_list(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *item, *head = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+ int i;
+
+ v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
+
+ visit_type_UserDefOneList(v, &head, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert(head != NULL);
+
+ for (i = 0, item = head; item; item = item->next, i++) {
+ char string[12];
+
+ snprintf(string, sizeof(string), "string%d", i);
+ g_assert_cmpstr(item->value->string, ==, string);
+ g_assert_cmpint(item->value->integer, ==, 42 + i);
+ }
+
+ qapi_free_UserDefOneList(head);
+}
+
+static void test_visitor_in_union(TestInputVisitorData *data,
+ const void *unused)
+{
+ Visitor *v;
+ Error *err = NULL;
+ UserDefUnion *tmp;
+
+ v = visitor_input_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
+
+ visit_type_UserDefUnion(v, &tmp, NULL, &err);
+ g_assert(err == NULL);
+ g_assert_cmpint(tmp->kind, ==, USER_DEF_UNION_KIND_B);
+ g_assert_cmpint(tmp->b->integer, ==, 42);
+ qapi_free_UserDefUnion(tmp);
+}
+
+static void input_visitor_test_add(const char *testpath,
+ TestInputVisitorData *data,
+ void (*test_func)(TestInputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
+ visitor_input_teardown);
+}
+
+static void test_visitor_in_errors(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ g_assert(p->string == NULL);
+
+ g_free(p->string);
+ g_free(p);
+}
+
+int main(int argc, char **argv)
+{
+ TestInputVisitorData in_visitor_data;
+
+ g_test_init(&argc, &argv, NULL);
+
+ input_visitor_test_add("/visitor/input/int",
+ &in_visitor_data, test_visitor_in_int);
+ input_visitor_test_add("/visitor/input/bool",
+ &in_visitor_data, test_visitor_in_bool);
+ input_visitor_test_add("/visitor/input/number",
+ &in_visitor_data, test_visitor_in_number);
+ input_visitor_test_add("/visitor/input/string",
+ &in_visitor_data, test_visitor_in_string);
+ input_visitor_test_add("/visitor/input/enum",
+ &in_visitor_data, test_visitor_in_enum);
+ input_visitor_test_add("/visitor/input/struct",
+ &in_visitor_data, test_visitor_in_struct);
+ input_visitor_test_add("/visitor/input/struct-nested",
+ &in_visitor_data, test_visitor_in_struct_nested);
+ input_visitor_test_add("/visitor/input/list",
+ &in_visitor_data, test_visitor_in_list);
+ input_visitor_test_add("/visitor/input/union",
+ &in_visitor_data, test_visitor_in_union);
+ input_visitor_test_add("/visitor/input/errors",
+ &in_visitor_data, test_visitor_in_errors);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
new file mode 100644
index 0000000..24a6359
--- /dev/null
+++ b/tests/test-qmp-output-visitor.c
@@ -0,0 +1,477 @@
+/*
+ * QMP Output Visitor unit-tests.
+ *
+ * Copyright (C) 2011 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+
+#include "qapi/qmp-output-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestOutputVisitorData {
+ QmpOutputVisitor *qov;
+ Visitor *ov;
+} TestOutputVisitorData;
+
+static void visitor_output_setup(TestOutputVisitorData *data,
+ const void *unused)
+{
+ data->qov = qmp_output_visitor_new();
+ g_assert(data->qov != NULL);
+
+ data->ov = qmp_output_get_visitor(data->qov);
+ g_assert(data->ov != NULL);
+}
+
+static void visitor_output_teardown(TestOutputVisitorData *data,
+ const void *unused)
+{
+ qmp_output_visitor_cleanup(data->qov);
+ data->qov = NULL;
+ data->ov = NULL;
+}
+
+static void test_visitor_out_int(TestOutputVisitorData *data,
+ const void *unused)
+{
+ int64_t value = -42;
+ Error *errp = NULL;
+ QObject *obj;
+
+ visit_type_int(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QINT);
+ g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, value);
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_bool(TestOutputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ bool value = true;
+ QObject *obj;
+
+ visit_type_bool(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QBOOL);
+ g_assert(qbool_get_int(qobject_to_qbool(obj)) == value);
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_number(TestOutputVisitorData *data,
+ const void *unused)
+{
+ double value = 3.14;
+ Error *errp = NULL;
+ QObject *obj;
+
+ visit_type_number(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QFLOAT);
+ g_assert(qfloat_get_double(qobject_to_qfloat(obj)) == value);
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_string(TestOutputVisitorData *data,
+ const void *unused)
+{
+ char *string = (char *) "Q E M U";
+ Error *errp = NULL;
+ QObject *obj;
+
+ visit_type_str(data->ov, &string, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, string);
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_no_string(TestOutputVisitorData *data,
+ const void *unused)
+{
+ char *string = NULL;
+ Error *errp = NULL;
+ QObject *obj;
+
+ /* A null string should return "" */
+ visit_type_str(data->ov, &string, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, "");
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_enum(TestOutputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ QObject *obj;
+ EnumOne i;
+
+ for (i = 0; i < ENUM_ONE_MAX; i++) {
+ visit_type_EnumOne(data->ov, &i, "unused", &errp);
+ g_assert(!error_is_set(&errp));
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==,
+ EnumOne_lookup[i]);
+ qobject_decref(obj);
+ }
+}
+
+static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
+ const void *unused)
+{
+ EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
+ Error *errp;
+
+ for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
+ errp = NULL;
+ visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
+ g_assert(error_is_set(&errp) == true);
+ error_free(errp);
+ }
+}
+
+typedef struct TestStruct
+{
+ int64_t integer;
+ bool boolean;
+ char *string;
+} TestStruct;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
+ const char *name, Error **errp)
+{
+ visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
+ errp);
+
+ visit_type_int(v, &(*obj)->integer, "integer", errp);
+ visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+ visit_type_str(v, &(*obj)->string, "string", errp);
+
+ visit_end_struct(v, errp);
+}
+
+static void test_visitor_out_struct(TestOutputVisitorData *data,
+ const void *unused)
+{
+ TestStruct test_struct = { .integer = 42,
+ .boolean = false,
+ .string = (char *) "foo"};
+ TestStruct *p = &test_struct;
+ Error *errp = NULL;
+ QObject *obj;
+ QDict *qdict;
+
+ visit_type_TestStruct(data->ov, &p, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QDICT);
+
+ qdict = qobject_to_qdict(obj);
+ g_assert_cmpint(qdict_size(qdict), ==, 3);
+ g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42);
+ g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, 0);
+ g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "foo");
+
+ QDECREF(qdict);
+}
+
+static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
+ const void *unused)
+{
+ int64_t value = 42;
+ Error *errp = NULL;
+ UserDefNested *ud2;
+ QObject *obj;
+ QDict *qdict, *dict1, *dict2, *dict3, *userdef;
+ const char *string = "user def string";
+ const char *strings[] = { "forty two", "forty three", "forty four",
+ "forty five" };
+
+ ud2 = g_malloc0(sizeof(*ud2));
+ ud2->string0 = g_strdup(strings[0]);
+
+ ud2->dict1.string1 = g_strdup(strings[1]);
+ ud2->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
+ ud2->dict1.dict2.userdef1->string = g_strdup(string);
+ ud2->dict1.dict2.userdef1->integer = value;
+ ud2->dict1.dict2.string2 = g_strdup(strings[2]);
+
+ ud2->dict1.has_dict3 = true;
+ ud2->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne));
+ ud2->dict1.dict3.userdef2->string = g_strdup(string);
+ ud2->dict1.dict3.userdef2->integer = value;
+ ud2->dict1.dict3.string3 = g_strdup(strings[3]);
+
+ visit_type_UserDefNested(data->ov, &ud2, "unused", &errp);
+ g_assert(!error_is_set(&errp));
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QDICT);
+
+ qdict = qobject_to_qdict(obj);
+ g_assert_cmpint(qdict_size(qdict), ==, 2);
+ g_assert_cmpstr(qdict_get_str(qdict, "string0"), ==, strings[0]);
+
+ dict1 = qdict_get_qdict(qdict, "dict1");
+ g_assert_cmpint(qdict_size(dict1), ==, 3);
+ g_assert_cmpstr(qdict_get_str(dict1, "string1"), ==, strings[1]);
+
+ dict2 = qdict_get_qdict(dict1, "dict2");
+ g_assert_cmpint(qdict_size(dict2), ==, 2);
+ g_assert_cmpstr(qdict_get_str(dict2, "string2"), ==, strings[2]);
+ userdef = qdict_get_qdict(dict2, "userdef1");
+ g_assert_cmpint(qdict_size(userdef), ==, 2);
+ g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
+ g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
+
+ dict3 = qdict_get_qdict(dict1, "dict3");
+ g_assert_cmpint(qdict_size(dict3), ==, 2);
+ g_assert_cmpstr(qdict_get_str(dict3, "string3"), ==, strings[3]);
+ userdef = qdict_get_qdict(dict3, "userdef2");
+ g_assert_cmpint(qdict_size(userdef), ==, 2);
+ g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
+ g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
+
+ QDECREF(qdict);
+ qapi_free_UserDefNested(ud2);
+}
+
+static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
+ const void *unused)
+{
+ EnumOne bad_values[] = { ENUM_ONE_MAX, -1 };
+ UserDefOne u = { 0 }, *pu = &u;
+ Error *errp;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
+ errp = NULL;
+ u.has_enum1 = true;
+ u.enum1 = bad_values[i];
+ visit_type_UserDefOne(data->ov, &pu, "unused", &errp);
+ g_assert(error_is_set(&errp) == true);
+ error_free(errp);
+ }
+}
+
+typedef struct TestStructList
+{
+ TestStruct *value;
+ struct TestStructList *next;
+} TestStructList;
+
+static void visit_type_TestStructList(Visitor *v, TestStructList **obj,
+ const char *name, Error **errp)
+{
+ GenericList *i, **head = (GenericList **)obj;
+
+ visit_start_list(v, name, errp);
+
+ for (*head = i = visit_next_list(v, head, errp); i; i = visit_next_list(v, &i, errp)) {
+ TestStructList *native_i = (TestStructList *)i;
+ visit_type_TestStruct(v, &native_i->value, NULL, errp);
+ }
+
+ visit_end_list(v, errp);
+}
+
+static void test_visitor_out_list(TestOutputVisitorData *data,
+ const void *unused)
+{
+ char *value_str = (char *) "list value";
+ TestStructList *p, *head = NULL;
+ const int max_items = 10;
+ bool value_bool = true;
+ int value_int = 10;
+ Error *errp = NULL;
+ QListEntry *entry;
+ QObject *obj;
+ QList *qlist;
+ int i;
+
+ for (i = 0; i < max_items; i++) {
+ p = g_malloc0(sizeof(*p));
+ p->value = g_malloc0(sizeof(*p->value));
+ p->value->integer = value_int;
+ p->value->boolean = value_bool;
+ p->value->string = value_str;
+
+ p->next = head;
+ head = p;
+ }
+
+ visit_type_TestStructList(data->ov, &head, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QLIST);
+
+ qlist = qobject_to_qlist(obj);
+ g_assert(!qlist_empty(qlist));
+
+ i = 0;
+ QLIST_FOREACH_ENTRY(qlist, entry) {
+ QDict *qdict;
+
+ g_assert(qobject_type(entry->value) == QTYPE_QDICT);
+ qdict = qobject_to_qdict(entry->value);
+ g_assert_cmpint(qdict_size(qdict), ==, 3);
+ g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int);
+ g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool);
+ g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str);
+ i++;
+ }
+ g_assert_cmpint(i, ==, max_items);
+
+ QDECREF(qlist);
+
+ for (p = head; p;) {
+ TestStructList *tmp = p->next;
+ g_free(p->value);
+ g_free(p);
+ p = tmp;
+ }
+}
+
+static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
+ const void *unused)
+{
+ UserDefNestedList *p, *head = NULL;
+ const char string[] = "foo bar";
+ int i, max_count = 1024;
+
+ for (i = 0; i < max_count; i++) {
+ p = g_malloc0(sizeof(*p));
+ p->value = g_malloc0(sizeof(*p->value));
+
+ p->value->string0 = g_strdup(string);
+ p->value->dict1.string1 = g_strdup(string);
+ p->value->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
+ p->value->dict1.dict2.userdef1->string = g_strdup(string);
+ p->value->dict1.dict2.userdef1->integer = 42;
+ p->value->dict1.dict2.string2 = g_strdup(string);
+ p->value->dict1.has_dict3 = false;
+
+ p->next = head;
+ head = p;
+ }
+
+ qapi_free_UserDefNestedList(head);
+}
+
+static void test_visitor_out_union(TestOutputVisitorData *data,
+ const void *unused)
+{
+ QObject *arg, *qvalue;
+ QDict *qdict, *value;
+
+ Error *err = NULL;
+
+ UserDefUnion *tmp = g_malloc0(sizeof(UserDefUnion));
+ tmp->kind = USER_DEF_UNION_KIND_A;
+ tmp->a = g_malloc0(sizeof(UserDefA));
+ tmp->a->boolean = true;
+
+ visit_type_UserDefUnion(data->ov, &tmp, NULL, &err);
+ g_assert(err == NULL);
+ arg = qmp_output_get_qobject(data->qov);
+
+ g_assert(qobject_type(arg) == QTYPE_QDICT);
+ qdict = qobject_to_qdict(arg);
+
+ g_assert_cmpstr(qdict_get_str(qdict, "type"), ==, "a");
+
+ qvalue = qdict_get(qdict, "data");
+ g_assert(data != NULL);
+ g_assert(qobject_type(qvalue) == QTYPE_QDICT);
+ value = qobject_to_qdict(qvalue);
+ g_assert_cmpint(qdict_get_bool(value, "boolean"), ==, true);
+
+ qapi_free_UserDefUnion(tmp);
+ QDECREF(qdict);
+}
+
+static void output_visitor_test_add(const char *testpath,
+ TestOutputVisitorData *data,
+ void (*test_func)(TestOutputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
+ test_func, visitor_output_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ TestOutputVisitorData out_visitor_data;
+
+ g_test_init(&argc, &argv, NULL);
+
+ output_visitor_test_add("/visitor/output/int",
+ &out_visitor_data, test_visitor_out_int);
+ output_visitor_test_add("/visitor/output/bool",
+ &out_visitor_data, test_visitor_out_bool);
+ output_visitor_test_add("/visitor/output/number",
+ &out_visitor_data, test_visitor_out_number);
+ output_visitor_test_add("/visitor/output/string",
+ &out_visitor_data, test_visitor_out_string);
+ output_visitor_test_add("/visitor/output/no-string",
+ &out_visitor_data, test_visitor_out_no_string);
+ output_visitor_test_add("/visitor/output/enum",
+ &out_visitor_data, test_visitor_out_enum);
+ output_visitor_test_add("/visitor/output/enum-errors",
+ &out_visitor_data, test_visitor_out_enum_errors);
+ output_visitor_test_add("/visitor/output/struct",
+ &out_visitor_data, test_visitor_out_struct);
+ output_visitor_test_add("/visitor/output/struct-nested",
+ &out_visitor_data, test_visitor_out_struct_nested);
+ output_visitor_test_add("/visitor/output/struct-errors",
+ &out_visitor_data, test_visitor_out_struct_errors);
+ output_visitor_test_add("/visitor/output/list",
+ &out_visitor_data, test_visitor_out_list);
+ output_visitor_test_add("/visitor/output/list-qapi-free",
+ &out_visitor_data, test_visitor_out_list_qapi_free);
+ output_visitor_test_add("/visitor/output/union",
+ &out_visitor_data, test_visitor_out_union);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c
new file mode 100644
index 0000000..5370e32
--- /dev/null
+++ b/tests/test-string-input-visitor.c
@@ -0,0 +1,195 @@
+/*
+ * String Input Visitor unit-tests.
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Authors:
+ * Paolo Bonzini <pbonzini at redhat.com> (based on test-qmp-input-visitor)
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <stdarg.h>
+
+#include "qapi/string-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestInputVisitorData {
+ StringInputVisitor *siv;
+} TestInputVisitorData;
+
+static void visitor_input_teardown(TestInputVisitorData *data,
+ const void *unused)
+{
+ if (data->siv) {
+ string_input_visitor_cleanup(data->siv);
+ data->siv = NULL;
+ }
+}
+
+/* This is provided instead of a test setup function so that the JSON
+ string used by the tests are kept in the test functions (and not
+ int main()) */
+static
+Visitor *visitor_input_test_init(TestInputVisitorData *data,
+ const char *string)
+{
+ Visitor *v;
+
+ data->siv = string_input_visitor_new(string);
+ g_assert(data->siv != NULL);
+
+ v = string_input_get_visitor(data->siv);
+ g_assert(v != NULL);
+
+ return v;
+}
+
+static void test_visitor_in_int(TestInputVisitorData *data,
+ const void *unused)
+{
+ int64_t res = 0, value = -42;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "-42");
+
+ visit_type_int(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, value);
+}
+
+static void test_visitor_in_bool(TestInputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ bool res = false;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "true");
+
+ visit_type_bool(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, true);
+ visitor_input_teardown(data, unused);
+
+ v = visitor_input_test_init(data, "yes");
+
+ visit_type_bool(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, true);
+ visitor_input_teardown(data, unused);
+
+ v = visitor_input_test_init(data, "on");
+
+ visit_type_bool(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, true);
+ visitor_input_teardown(data, unused);
+
+ v = visitor_input_test_init(data, "false");
+
+ visit_type_bool(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, false);
+ visitor_input_teardown(data, unused);
+
+ v = visitor_input_test_init(data, "no");
+
+ visit_type_bool(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, false);
+ visitor_input_teardown(data, unused);
+
+ v = visitor_input_test_init(data, "off");
+
+ visit_type_bool(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, false);
+}
+
+static void test_visitor_in_number(TestInputVisitorData *data,
+ const void *unused)
+{
+ double res = 0, value = 3.14;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "3.14");
+
+ visit_type_number(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpfloat(res, ==, value);
+}
+
+static void test_visitor_in_string(TestInputVisitorData *data,
+ const void *unused)
+{
+ char *res = NULL, *value = (char *) "Q E M U";
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, value);
+
+ visit_type_str(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpstr(res, ==, value);
+
+ g_free(res);
+}
+
+static void test_visitor_in_enum(TestInputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ Visitor *v;
+ EnumOne i;
+
+ for (i = 0; EnumOne_lookup[i]; i++) {
+ EnumOne res = -1;
+
+ v = visitor_input_test_init(data, EnumOne_lookup[i]);
+
+ visit_type_EnumOne(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(i, ==, res);
+
+ visitor_input_teardown(data, NULL);
+ }
+
+ data->siv = NULL;
+}
+
+static void input_visitor_test_add(const char *testpath,
+ TestInputVisitorData *data,
+ void (*test_func)(TestInputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
+ visitor_input_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ TestInputVisitorData in_visitor_data;
+
+ g_test_init(&argc, &argv, NULL);
+
+ input_visitor_test_add("/string-visitor/input/int",
+ &in_visitor_data, test_visitor_in_int);
+ input_visitor_test_add("/string-visitor/input/bool",
+ &in_visitor_data, test_visitor_in_bool);
+ input_visitor_test_add("/string-visitor/input/number",
+ &in_visitor_data, test_visitor_in_number);
+ input_visitor_test_add("/string-visitor/input/string",
+ &in_visitor_data, test_visitor_in_string);
+ input_visitor_test_add("/string-visitor/input/enum",
+ &in_visitor_data, test_visitor_in_enum);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c
new file mode 100644
index 0000000..22909b8
--- /dev/null
+++ b/tests/test-string-output-visitor.c
@@ -0,0 +1,188 @@
+/*
+ * String Output Visitor unit-tests.
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Authors:
+ * Paolo Bonzini <pbonzini at redhat.com> (based on test-qmp-output-visitor)
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+
+#include "qapi/string-output-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestOutputVisitorData {
+ StringOutputVisitor *sov;
+ Visitor *ov;
+} TestOutputVisitorData;
+
+static void visitor_output_setup(TestOutputVisitorData *data,
+ const void *unused)
+{
+ data->sov = string_output_visitor_new();
+ g_assert(data->sov != NULL);
+
+ data->ov = string_output_get_visitor(data->sov);
+ g_assert(data->ov != NULL);
+}
+
+static void visitor_output_teardown(TestOutputVisitorData *data,
+ const void *unused)
+{
+ string_output_visitor_cleanup(data->sov);
+ data->sov = NULL;
+ data->ov = NULL;
+}
+
+static void test_visitor_out_int(TestOutputVisitorData *data,
+ const void *unused)
+{
+ int64_t value = -42;
+ Error *errp = NULL;
+ char *str;
+
+ visit_type_int(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ str = string_output_get_string(data->sov);
+ g_assert(str != NULL);
+ g_assert_cmpstr(str, ==, "-42");
+ g_free(str);
+}
+
+static void test_visitor_out_bool(TestOutputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ bool value = true;
+ char *str;
+
+ visit_type_bool(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ str = string_output_get_string(data->sov);
+ g_assert(str != NULL);
+ g_assert_cmpstr(str, ==, "true");
+ g_free(str);
+}
+
+static void test_visitor_out_number(TestOutputVisitorData *data,
+ const void *unused)
+{
+ double value = 3.14;
+ Error *errp = NULL;
+ char *str;
+
+ visit_type_number(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ str = string_output_get_string(data->sov);
+ g_assert(str != NULL);
+ g_assert_cmpstr(str, ==, "3.14");
+ g_free(str);
+}
+
+static void test_visitor_out_string(TestOutputVisitorData *data,
+ const void *unused)
+{
+ char *string = (char *) "Q E M U";
+ Error *errp = NULL;
+ char *str;
+
+ visit_type_str(data->ov, &string, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ str = string_output_get_string(data->sov);
+ g_assert(str != NULL);
+ g_assert_cmpstr(str, ==, string);
+ g_free(str);
+}
+
+static void test_visitor_out_no_string(TestOutputVisitorData *data,
+ const void *unused)
+{
+ char *string = NULL;
+ Error *errp = NULL;
+ char *str;
+
+ /* A null string should return "" */
+ visit_type_str(data->ov, &string, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ str = string_output_get_string(data->sov);
+ g_assert(str != NULL);
+ g_assert_cmpstr(str, ==, "");
+ g_free(str);
+}
+
+static void test_visitor_out_enum(TestOutputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ char *str;
+ EnumOne i;
+
+ for (i = 0; i < ENUM_ONE_MAX; i++) {
+ visit_type_EnumOne(data->ov, &i, "unused", &errp);
+ g_assert(!error_is_set(&errp));
+
+ str = string_output_get_string(data->sov);
+ g_assert(str != NULL);
+ g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
+ g_free(str);
+ }
+}
+
+static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
+ const void *unused)
+{
+ EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
+ Error *errp;
+
+ for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
+ errp = NULL;
+ visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
+ g_assert(error_is_set(&errp) == true);
+ error_free(errp);
+ }
+}
+
+static void output_visitor_test_add(const char *testpath,
+ TestOutputVisitorData *data,
+ void (*test_func)(TestOutputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
+ test_func, visitor_output_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ TestOutputVisitorData out_visitor_data;
+
+ g_test_init(&argc, &argv, NULL);
+
+ output_visitor_test_add("/string-visitor/output/int",
+ &out_visitor_data, test_visitor_out_int);
+ output_visitor_test_add("/string-visitor/output/bool",
+ &out_visitor_data, test_visitor_out_bool);
+ output_visitor_test_add("/string-visitor/output/number",
+ &out_visitor_data, test_visitor_out_number);
+ output_visitor_test_add("/string-visitor/output/string",
+ &out_visitor_data, test_visitor_out_string);
+ output_visitor_test_add("/string-visitor/output/no-string",
+ &out_visitor_data, test_visitor_out_no_string);
+ output_visitor_test_add("/string-visitor/output/enum",
+ &out_visitor_data, test_visitor_out_enum);
+ output_visitor_test_add("/string-visitor/output/enum-errors",
+ &out_visitor_data, test_visitor_out_enum_errors);
+
+ g_test_run();
+
+ return 0;
+}
commit 703e01e6e249e6d0a74e0cbab827b235032ec7f3
Author: Alon Levy <alevy at redhat.com>
Date: Thu Mar 29 23:35:36 2012 +0200
tracetool: dtrace: handle in and next reserved words
Signed-off-by: Alon Levy <alevy at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/scripts/tracetool b/scripts/tracetool
index a279c2c..5e77aa2 100755
--- a/scripts/tracetool
+++ b/scripts/tracetool
@@ -506,10 +506,12 @@ EOF
i=1
for arg in $arglist
do
- # 'limit' is a reserved keyword
- if [ "$arg" = "limit" ]; then
- arg="_limit"
- fi
+ # postfix reserved words with '_'
+ case "$arg" in
+ limit|in|next|self)
+ arg="${arg}_"
+ ;;
+ esac
cat <<EOF
$arg = \$arg$i;
EOF
commit 60be795f0b9ca06030b942367a82d80f125a50f7
Author: Lee Essen <lee.essen at nowonline.co.uk>
Date: Tue Mar 20 17:02:40 2012 +0000
tracetool: dtrace disabled-events fix
If there are "disabled" entries in the trace-events file then
linetod_nop() is called if the backend is dtrace, it's currently
not present. Also equivalent fix for stap.
Signed-off-by: Lee Essen <lee.essen at nowonline.co.uk>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/scripts/tracetool b/scripts/tracetool
index 65bd0a1..a279c2c 100755
--- a/scripts/tracetool
+++ b/scripts/tracetool
@@ -161,6 +161,18 @@ linetoc_nop()
return
}
+linetod_nop()
+{
+ # Used when "disabled" events are processed
+ return
+}
+
+linetostap_nop()
+{
+ # Used when "disabled" events are processed
+ return
+}
+
linetoc_end_nop()
{
return
commit 2174e2380fcf853977a73be935b369218671a9a6
Author: Alon Levy <alevy at redhat.com>
Date: Sun Mar 18 08:47:15 2012 +0100
Makefile.target: code stp dependency on trace-events
Signed-off-by: Alon Levy <alevy at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/Makefile.target b/Makefile.target
index 44b2e83..9f3c100 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -58,7 +58,7 @@ else
TARGET_TYPE=system
endif
-$(QEMU_PROG).stp:
+$(QEMU_PROG).stp: $(SRC_PATH)/trace-events
$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \
--$(TRACE_BACKEND) \
--binary $(bindir)/$(QEMU_PROG) \
commit b0f26631bc51790069b0c0b3935b20f9a54e3ab3
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 10:31:23 2012 +0000
pl031: switch clock base to rtc_clock
This lets the user specify the desired semantics. By default, the RTC
will follow adjustments from the host's NTP client, and will remain in
sync when the virtual machine is stopped. The previous behavior, which
provides determinism with both icount and qtest, remains available with
"-rtc clock=vm".
pl031 supports migration, so we need to convert the time base from
rtc_clock to vm_clock and back for backwards compatibility. (The
rtc_clock may not be synchronized on the two machines, especially with
savevm/loadvm, so the conversion is needed anyway. And since any time
base will do, why not pick the one base that is backwards compatible).
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/pl031.c b/hw/pl031.c
index 713f85d..9602664 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -13,6 +13,7 @@
#include "sysbus.h"
#include "qemu-timer.h"
+#include "sysemu.h"
//#define DEBUG_PL031
@@ -38,6 +39,11 @@ typedef struct {
QEMUTimer *timer;
qemu_irq irq;
+ /* Needed to preserve the tick_count across migration, even if the
+ * absolute value of the rtc_clock is different on the source and
+ * destination.
+ */
+ uint32_t tick_offset_vmstate;
uint32_t tick_offset;
uint32_t mr;
@@ -68,27 +74,23 @@ static void pl031_interrupt(void * opaque)
static uint32_t pl031_get_count(pl031_state *s)
{
- /* This assumes qemu_get_clock_ns returns the time since the machine was
- created. */
- return s->tick_offset + qemu_get_clock_ns(vm_clock) / get_ticks_per_sec();
+ int64_t now = qemu_get_clock_ns(rtc_clock);
+ return s->tick_offset + now / get_ticks_per_sec();
}
static void pl031_set_alarm(pl031_state *s)
{
- int64_t now;
uint32_t ticks;
- now = qemu_get_clock_ns(vm_clock);
- ticks = s->tick_offset + now / get_ticks_per_sec();
-
/* The timer wraps around. This subtraction also wraps in the same way,
and gives correct results when alarm < now_ticks. */
- ticks = s->mr - ticks;
+ ticks = s->mr - pl031_get_count(s);
DPRINTF("Alarm set in %ud ticks\n", ticks);
if (ticks == 0) {
qemu_del_timer(s->timer);
pl031_interrupt(s);
} else {
+ int64_t now = qemu_get_clock_ns(rtc_clock);
qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec());
}
}
@@ -190,18 +192,29 @@ static int pl031_init(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
- /* ??? We assume vm_clock is zero at this point. */
qemu_get_timedate(&tm, 0);
- s->tick_offset = mktimegm(&tm);
+ s->tick_offset = mktimegm(&tm) - qemu_get_clock_ns(rtc_clock) / get_ticks_per_sec();
- s->timer = qemu_new_timer_ns(vm_clock, pl031_interrupt, s);
+ s->timer = qemu_new_timer_ns(rtc_clock, pl031_interrupt, s);
return 0;
}
+static void pl031_pre_save(void *opaque)
+{
+ pl031_state *s = opaque;
+
+ /* tick_offset is base_time - rtc_clock base time. Instead, we want to
+ * store the base time relative to the vm_clock for backwards-compatibility. */
+ int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock);
+ s->tick_offset_vmstate = s->tick_offset + delta / get_ticks_per_sec();
+}
+
static int pl031_post_load(void *opaque, int version_id)
{
pl031_state *s = opaque;
+ int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock);
+ s->tick_offset = s->tick_offset_vmstate - delta / get_ticks_per_sec();
pl031_set_alarm(s);
return 0;
}
@@ -210,9 +223,10 @@ static const VMStateDescription vmstate_pl031 = {
.name = "pl031",
.version_id = 1,
.minimum_version_id = 1,
+ .pre_save = pl031_pre_save,
.post_load = pl031_post_load,
.fields = (VMStateField[]) {
- VMSTATE_UINT32(tick_offset, pl031_state),
+ VMSTATE_UINT32(tick_offset_vmstate, pl031_state),
VMSTATE_UINT32(mr, pl031_state),
VMSTATE_UINT32(lr, pl031_state),
VMSTATE_UINT32(cr, pl031_state),
commit ac204b8f67d17881bd61f2439005d02b1de3736e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 10:31:22 2012 +0000
pl031: rearm alarm timer upon load
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/pl031.c b/hw/pl031.c
index 69abc4f..713f85d 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -47,21 +47,6 @@ typedef struct {
uint32_t is;
} pl031_state;
-static const VMStateDescription vmstate_pl031 = {
- .name = "pl031",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(tick_offset, pl031_state),
- VMSTATE_UINT32(mr, pl031_state),
- VMSTATE_UINT32(lr, pl031_state),
- VMSTATE_UINT32(cr, pl031_state),
- VMSTATE_UINT32(im, pl031_state),
- VMSTATE_UINT32(is, pl031_state),
- VMSTATE_END_OF_LIST()
- }
-};
-
static const unsigned char pl031_id[] = {
0x31, 0x10, 0x14, 0x00, /* Device ID */
0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */
@@ -213,6 +198,30 @@ static int pl031_init(SysBusDevice *dev)
return 0;
}
+static int pl031_post_load(void *opaque, int version_id)
+{
+ pl031_state *s = opaque;
+
+ pl031_set_alarm(s);
+ return 0;
+}
+
+static const VMStateDescription vmstate_pl031 = {
+ .name = "pl031",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = pl031_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(tick_offset, pl031_state),
+ VMSTATE_UINT32(mr, pl031_state),
+ VMSTATE_UINT32(lr, pl031_state),
+ VMSTATE_UINT32(cr, pl031_state),
+ VMSTATE_UINT32(im, pl031_state),
+ VMSTATE_UINT32(is, pl031_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void pl031_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
commit 348abc86c8f4b07264b0ff939394b878a3beace1
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 10:31:22 2012 +0000
arm: switch real-time clocks to rtc_clock
This lets the user specify the desired semantics. By default, the RTC
will follow adjustments from the host's NTP client. "-rtc clock=vm" will
improve determinism with both icount and qtest. Finally, the previous
behavior is available with "-rtc clock=rt".
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/omap1.c b/hw/omap1.c
index 39e731a..80d47f0 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -2888,7 +2888,7 @@ static void omap_rtc_reset(struct omap_rtc_s *s)
s->pm_am = 0;
s->auto_comp = 0;
s->round = 0;
- s->tick = qemu_get_clock_ms(rt_clock);
+ s->tick = qemu_get_clock_ms(rtc_clock);
memset(&s->alarm_tm, 0, sizeof(s->alarm_tm));
s->alarm_tm.tm_mday = 0x01;
s->status = 1 << 7;
@@ -2909,7 +2909,7 @@ static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory,
s->irq = timerirq;
s->alarm = alarmirq;
- s->clk = qemu_new_timer_ms(rt_clock, omap_rtc_tick, s);
+ s->clk = qemu_new_timer_ms(rtc_clock, omap_rtc_tick, s);
omap_rtc_reset(s);
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 1d5c35f..ddaa846 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -875,7 +875,7 @@ static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s)
static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s)
{
- int64_t rt = qemu_get_clock_ms(rt_clock);
+ int64_t rt = qemu_get_clock_ms(rtc_clock);
s->last_rcnr += ((rt - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
s->last_rdcr += ((rt - s->last_hz) << 15) /
@@ -885,7 +885,7 @@ static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s)
static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s)
{
- int64_t rt = qemu_get_clock_ms(rt_clock);
+ int64_t rt = qemu_get_clock_ms(rtc_clock);
if (s->rtsr & (1 << 12))
s->last_swcr += (rt - s->last_sw) / 10;
s->last_sw = rt;
@@ -893,7 +893,7 @@ static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s)
static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s)
{
- int64_t rt = qemu_get_clock_ms(rt_clock);
+ int64_t rt = qemu_get_clock_ms(rtc_clock);
if (s->rtsr & (1 << 15))
s->last_swcr += rt - s->last_pi;
s->last_pi = rt;
@@ -1019,16 +1019,16 @@ static uint64_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr,
case PIAR:
return s->piar;
case RCNR:
- return s->last_rcnr + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
+ return s->last_rcnr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
case RDCR:
- return s->last_rdcr + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
+ return s->last_rdcr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
case RYCR:
return s->last_rycr;
case SWCR:
if (s->rtsr & (1 << 12))
- return s->last_swcr + (qemu_get_clock_ms(rt_clock) - s->last_sw) / 10;
+ return s->last_swcr + (qemu_get_clock_ms(rtc_clock) - s->last_sw) / 10;
else
return s->last_swcr;
default:
@@ -1168,14 +1168,14 @@ static int pxa2xx_rtc_init(SysBusDevice *dev)
s->last_swcr = (tm.tm_hour << 19) |
(tm.tm_min << 13) | (tm.tm_sec << 7);
s->last_rtcpicr = 0;
- s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rt_clock);
-
- s->rtc_hz = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_hz_tick, s);
- s->rtc_rdal1 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_rdal1_tick, s);
- s->rtc_rdal2 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_rdal2_tick, s);
- s->rtc_swal1 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_swal1_tick, s);
- s->rtc_swal2 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_swal2_tick, s);
- s->rtc_pi = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_pi_tick, s);
+ s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rtc_clock);
+
+ s->rtc_hz = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_hz_tick, s);
+ s->rtc_rdal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s);
+ s->rtc_rdal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s);
+ s->rtc_swal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s);
+ s->rtc_swal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s);
+ s->rtc_pi = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_pi_tick, s);
sysbus_init_irq(dev, &s->rtc_irq);
diff --git a/hw/strongarm.c b/hw/strongarm.c
index 4d5b60f..1b15f39 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -255,7 +255,7 @@ static inline void strongarm_rtc_int_update(StrongARMRTCState *s)
static void strongarm_rtc_hzupdate(StrongARMRTCState *s)
{
- int64_t rt = qemu_get_clock_ms(rt_clock);
+ int64_t rt = qemu_get_clock_ms(rtc_clock);
s->last_rcnr += ((rt - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
s->last_hz = rt;
@@ -308,7 +308,7 @@ static uint64_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr,
return s->rtar;
case RCNR:
return s->last_rcnr +
- ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
+ ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
default:
printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
@@ -374,10 +374,10 @@ static int strongarm_rtc_init(SysBusDevice *dev)
qemu_get_timedate(&tm, 0);
s->last_rcnr = (uint32_t) mktimegm(&tm);
- s->last_hz = qemu_get_clock_ms(rt_clock);
+ s->last_hz = qemu_get_clock_ms(rtc_clock);
- s->rtc_alarm = qemu_new_timer_ms(rt_clock, strongarm_rtc_alarm_tick, s);
- s->rtc_hz = qemu_new_timer_ms(rt_clock, strongarm_rtc_hz_tick, s);
+ s->rtc_alarm = qemu_new_timer_ms(rtc_clock, strongarm_rtc_alarm_tick, s);
+ s->rtc_hz = qemu_new_timer_ms(rtc_clock, strongarm_rtc_hz_tick, s);
sysbus_init_irq(dev, &s->rtc_irq);
sysbus_init_irq(dev, &s->rtc_hz_irq);
diff --git a/hw/twl92230.c b/hw/twl92230.c
index 22da6f8..0d70d84 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -22,6 +22,7 @@
#include "hw.h"
#include "qemu-timer.h"
#include "i2c.h"
+#include "sysemu.h"
#include "console.h"
#define VERBOSE 1
@@ -71,14 +72,14 @@ static inline void menelaus_update(MenelausState *s)
static inline void menelaus_rtc_start(MenelausState *s)
{
- s->rtc.next += qemu_get_clock_ms(rt_clock);
+ s->rtc.next += qemu_get_clock_ms(rtc_clock);
qemu_mod_timer(s->rtc.hz_tm, s->rtc.next);
}
static inline void menelaus_rtc_stop(MenelausState *s)
{
qemu_del_timer(s->rtc.hz_tm);
- s->rtc.next -= qemu_get_clock_ms(rt_clock);
+ s->rtc.next -= qemu_get_clock_ms(rtc_clock);
if (s->rtc.next < 1)
s->rtc.next = 1;
}
@@ -781,7 +782,7 @@ static void menelaus_pre_save(void *opaque)
{
MenelausState *s = opaque;
/* Should be <= 1000 */
- s->rtc_next_vmstate = s->rtc.next - qemu_get_clock_ms(rt_clock);
+ s->rtc_next_vmstate = s->rtc.next - qemu_get_clock_ms(rtc_clock);
}
static int menelaus_post_load(void *opaque, int version_id)
@@ -842,7 +843,7 @@ static int twl92230_init(I2CSlave *i2c)
{
MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c);
- s->rtc.hz_tm = qemu_new_timer_ms(rt_clock, menelaus_rtc_hz, s);
+ s->rtc.hz_tm = qemu_new_timer_ms(rtc_clock, menelaus_rtc_hz, s);
/* Three output pins plus one interrupt pin. */
qdev_init_gpio_out(&i2c->qdev, s->out, 4);
commit e230d4e8bd79a7a7b6d431d6659fa0234f95c82d
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 10:31:22 2012 +0000
omap: switch omap_lpg to vm_clock
The output of the pulse generator needs to be deterministic when
running in -icount mode, and to remain constant whenever the VM is
stopped. So the right clock to use is vm_clock.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/omap1.c b/hw/omap1.c
index 2a341bf..39e731a 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3497,9 +3497,9 @@ static void omap_lpg_tick(void *opaque)
struct omap_lpg_s *s = opaque;
if (s->cycle)
- qemu_mod_timer(s->tm, qemu_get_clock_ms(rt_clock) + s->period - s->on);
+ qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->period - s->on);
else
- qemu_mod_timer(s->tm, qemu_get_clock_ms(rt_clock) + s->on);
+ qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->on);
s->cycle = !s->cycle;
printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off");
@@ -3617,7 +3617,7 @@ static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory,
struct omap_lpg_s *s = (struct omap_lpg_s *)
g_malloc0(sizeof(struct omap_lpg_s));
- s->tm = qemu_new_timer_ms(rt_clock, omap_lpg_tick, s);
+ s->tm = qemu_new_timer_ms(vm_clock, omap_lpg_tick, s);
omap_lpg_reset(s);
commit 788081417ae250e69bfa1d33d11d774bc4c03a27
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Mar 30 10:31:21 2012 +0000
rtc: add -rtc clock=rt
This will let people use backwards-compatible semantics for devices that
will be affected by the following patches.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/qemu-options.hx b/qemu-options.hx
index 662f571..a6cd8e9 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2453,7 +2453,7 @@ DEF("localtime", 0, QEMU_OPTION_localtime, "", QEMU_ARCH_ALL)
DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, "", QEMU_ARCH_ALL)
DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \
- "-rtc [base=utc|localtime|date][,clock=host|vm][,driftfix=none|slew]\n" \
+ "-rtc [base=utc|localtime|date][,clock=host|rt|vm][,driftfix=none|slew]\n" \
" set the RTC base and clock, enable drift fix for clock ticks (x86 only)\n",
QEMU_ARCH_ALL)
@@ -2469,8 +2469,9 @@ format @code{2006-06-17T16:01:21} or @code{2006-06-17}. The default base is UTC.
By default the RTC is driven by the host system time. This allows to use the
RTC as accurate reference clock inside the guest, specifically if the host
time is smoothly following an accurate external reference clock, e.g. via NTP.
-If you want to isolate the guest time from the host, even prevent it from
-progressing during suspension, you can set @option{clock} to @code{vm} instead.
+If you want to isolate the guest time from the host, you can set @option{clock}
+to @code{rt} instead. To even prevent it from progressing during suspension,
+you can set it to @code{vm}.
Enable @option{driftfix} (i386 targets only) if you experience time drift problems,
specifically with Windows' ACPI HAL. This option will try to figure out how
diff --git a/vl.c b/vl.c
index 0fccf50..71a4755 100644
--- a/vl.c
+++ b/vl.c
@@ -529,6 +529,8 @@ static void configure_rtc(QemuOpts *opts)
if (value) {
if (!strcmp(value, "host")) {
rtc_clock = host_clock;
+ } else if (!strcmp(value, "rt")) {
+ rtc_clock = rt_clock;
} else if (!strcmp(value, "vm")) {
rtc_clock = vm_clock;
} else {
commit 06ed5d66f77f2794344c7dfd3d21a07e97f0b8fa
Author: Andrew Towers <atowers at gmail.com>
Date: Thu Mar 29 02:41:08 2012 +0000
ARM: Permit any ARMv6K CPU to read the MVFR0 and MVFR1 VFP registers.
This patch replaces the ARM_FEATURE_VFP3 test when reading MVFR registers
with a test for a new feature flag ARM_FEATURE_MVFR, and sets this feature
for all ARMv6K cores (ARM1156 is not a v6K core, yet supports MVFR; qemu
does not support ARM1156 at this time.)
MVFR0 and MVFR1 were introduced in ARM1136JF-S r1p0 (ARMv6K, VFPv2) and are
present in ARM1156T2F-S (non-v6K), ARM1176JZF-S, ARM11MPCore and newer cores.
Reference: ARM DDI 0211H, 0290G, 0301H, 0360E.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Ffbefjag.html
Without this change, the linux kernel will not boot with VFP support enabled
under ARM1176 system emulation, due to the unconditional use of MVFR1 at the
end of vfp_init() in arch/arm/vfp/vfpmodule.c:
VFP support v0.3: implemetor 41 architecture 1 part 20 variant b rev 5
Internal error: Oops - undefined instruction: 0 [#1]
Signed-off-by: Andrew Towers <atowers at gmail.com>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index a68df61..e176c5f 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -382,6 +382,7 @@ enum arm_features {
ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */
ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */
ARM_FEATURE_GENERIC_TIMER,
+ ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */
};
static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index dd8e306..d974b57 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -254,6 +254,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
}
if (arm_feature(env, ARM_FEATURE_V6K)) {
set_feature(env, ARM_FEATURE_V6);
+ set_feature(env, ARM_FEATURE_MVFR);
}
if (arm_feature(env, ARM_FEATURE_V6)) {
set_feature(env, ARM_FEATURE_V5);
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 81725d1..46d1d3e 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -2906,7 +2906,7 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
case ARM_VFP_MVFR0:
case ARM_VFP_MVFR1:
if (IS_USER(s)
- || !arm_feature(env, ARM_FEATURE_VFP3))
+ || !arm_feature(env, ARM_FEATURE_MVFR))
return 1;
tmp = load_cpu_field(vfp.xregs[rn]);
break;
commit 8df9082da6b7a24b299d37462bc3539c15f26135
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Mar 29 18:03:18 2012 +0200
target-unicore32: Move CPU-dependent init into initfn
Instead of setting values in a CPUID switch, do so in initfn functions.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Guan Xuetao <gxt at mprc.pku.edu.cn>
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index 189b6f6..de63f58 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -15,6 +15,11 @@
#include "cpu-qom.h"
#include "qemu-common.h"
+static inline void set_feature(CPUUniCore32State *env, int feature)
+{
+ env->features |= feature;
+}
+
/* CPU models */
typedef struct UniCore32CPUInfo {
@@ -28,6 +33,12 @@ static void unicore_ii_cpu_initfn(Object *obj)
CPUUniCore32State *env = &cpu->env;
env->cp0.c0_cpuid = 0x40010863;
+
+ set_feature(env, UC32_HWCAP_CMOV);
+ set_feature(env, UC32_HWCAP_UCF64);
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
+ env->cp0.c0_cachetype = 0x1dd20d2;
+ env->cp0.c1_sys = 0x00090078;
}
static void uc32_any_cpu_initfn(Object *obj)
@@ -36,6 +47,9 @@ static void uc32_any_cpu_initfn(Object *obj)
CPUUniCore32State *env = &cpu->env;
env->cp0.c0_cpuid = 0xffffffff;
+
+ set_feature(env, UC32_HWCAP_CMOV);
+ set_feature(env, UC32_HWCAP_UCF64);
}
static const UniCore32CPUInfo uc32_cpus[] = {
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 0f23a40..9fe4a37 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -14,16 +14,10 @@
#include "helper.h"
#include "host-utils.h"
-static inline void set_feature(CPUUniCore32State *env, int feature)
-{
- env->features |= feature;
-}
-
CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
{
UniCore32CPU *cpu;
CPUUniCore32State *env;
- uint32_t id;
static int inited = 1;
if (object_class_by_name(cpu_model) == NULL) {
@@ -32,23 +26,6 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
cpu = UNICORE32_CPU(object_new(cpu_model));
env = &cpu->env;
- id = env->cp0.c0_cpuid;
- switch (id) {
- case UC32_CPUID_UCV2:
- set_feature(env, UC32_HWCAP_CMOV);
- set_feature(env, UC32_HWCAP_UCF64);
- env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
- env->cp0.c0_cachetype = 0x1dd20d2;
- env->cp0.c1_sys = 0x00090078;
- break;
- case UC32_CPUID_ANY: /* For userspace emulation. */
- set_feature(env, UC32_HWCAP_CMOV);
- set_feature(env, UC32_HWCAP_UCF64);
- break;
- default:
- cpu_abort(env, "Bad CPU ID: %x\n", id);
- }
-
if (inited) {
inited = 0;
uc32_translate_init();
commit ae0f5e9ea80de923ae1c11289cf6ac468f657880
Author: Andreas Färber <afaerber at suse.de>
Date: Tue Feb 14 01:16:17 2012 +0100
target-unicore32: QOM'ify CPU
Embed CPUUniCore32State as first member of UniCore32CPU.
Contributed under GPLv2+.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Guan Xuetao <gxt at mprc.pku.edu.cn>
diff --git a/Makefile.target b/Makefile.target
index 44b2e83..7cff65f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -98,6 +98,7 @@ libobj-y += cpu_init.o
endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
+libobj-$(TARGET_UNICORE32) += cpu.o
libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
libobj-y += disas.o
diff --git a/target-unicore32/cpu-qom.h b/target-unicore32/cpu-qom.h
new file mode 100644
index 0000000..342d85e
--- /dev/null
+++ b/target-unicore32/cpu-qom.h
@@ -0,0 +1,59 @@
+/*
+ * QEMU UniCore32 CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_UC32_CPU_QOM_H
+#define QEMU_UC32_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_UNICORE32_CPU "unicore32-cpu"
+
+#define UNICORE32_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(UniCore32CPUClass, (klass), TYPE_UNICORE32_CPU)
+#define UNICORE32_CPU(obj) \
+ OBJECT_CHECK(UniCore32CPU, (obj), TYPE_UNICORE32_CPU)
+#define UNICORE32_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(UniCore32CPUClass, (obj), TYPE_UNICORE32_CPU)
+
+/**
+ * UniCore32CPUClass:
+ *
+ * A UniCore32 CPU model.
+ */
+typedef struct UniCore32CPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+} UniCore32CPUClass;
+
+/**
+ * UniCore32CPU:
+ * @env: #CPUUniCore32State
+ *
+ * A UniCore32 CPU.
+ */
+typedef struct UniCore32CPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUUniCore32State env;
+} UniCore32CPU;
+
+static inline UniCore32CPU *uc32_env_get_cpu(CPUUniCore32State *env)
+{
+ return UNICORE32_CPU(container_of(env, UniCore32CPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(uc32_env_get_cpu(e))
+
+
+#endif
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
new file mode 100644
index 0000000..189b6f6
--- /dev/null
+++ b/target-unicore32/cpu.c
@@ -0,0 +1,90 @@
+/*
+ * QEMU UniCore32 CPU
+ *
+ * Copyright (c) 2010-2011 GUAN Xue-tao
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Contributions from 2012-04-01 on are considered under GPL version 2,
+ * or (at your option) any later version.
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+
+/* CPU models */
+
+typedef struct UniCore32CPUInfo {
+ const char *name;
+ void (*instance_init)(Object *obj);
+} UniCore32CPUInfo;
+
+static void unicore_ii_cpu_initfn(Object *obj)
+{
+ UniCore32CPU *cpu = UNICORE32_CPU(obj);
+ CPUUniCore32State *env = &cpu->env;
+
+ env->cp0.c0_cpuid = 0x40010863;
+}
+
+static void uc32_any_cpu_initfn(Object *obj)
+{
+ UniCore32CPU *cpu = UNICORE32_CPU(obj);
+ CPUUniCore32State *env = &cpu->env;
+
+ env->cp0.c0_cpuid = 0xffffffff;
+}
+
+static const UniCore32CPUInfo uc32_cpus[] = {
+ { .name = "UniCore-II", .instance_init = unicore_ii_cpu_initfn },
+ { .name = "any", .instance_init = uc32_any_cpu_initfn },
+};
+
+static void uc32_cpu_initfn(Object *obj)
+{
+ UniCore32CPU *cpu = UNICORE32_CPU(obj);
+ CPUUniCore32State *env = &cpu->env;
+
+ cpu_exec_init(env);
+ env->cpu_model_str = object_get_typename(obj);
+
+ env->uncached_asr = ASR_MODE_USER;
+ env->regs[31] = 0;
+
+ tlb_flush(env, 1);
+}
+
+static void uc32_register_cpu_type(const UniCore32CPUInfo *info)
+{
+ TypeInfo type_info = {
+ .name = info->name,
+ .parent = TYPE_UNICORE32_CPU,
+ .instance_init = info->instance_init,
+ };
+
+ type_register_static(&type_info);
+}
+
+static const TypeInfo uc32_cpu_type_info = {
+ .name = TYPE_UNICORE32_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(UniCore32CPU),
+ .instance_init = uc32_cpu_initfn,
+ .abstract = true,
+ .class_size = sizeof(UniCore32CPUClass),
+};
+
+static void uc32_cpu_register_types(void)
+{
+ int i;
+
+ type_register_static(&uc32_cpu_type_info);
+ for (i = 0; i < ARRAY_SIZE(uc32_cpus); i++) {
+ uc32_register_cpu_type(&uc32_cpus[i]);
+ }
+}
+
+type_init(uc32_cpu_register_types)
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 8ec0d2f..81c14ff 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -160,6 +160,7 @@ static inline void cpu_set_tls(CPUUniCore32State *env, target_ulong newtls)
}
#include "cpu-all.h"
+#include "cpu-qom.h"
#include "exec-all.h"
static inline void cpu_pc_from_tb(CPUUniCore32State *env, TranslationBlock *tb)
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 18a9cbb..0f23a40 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -19,43 +19,20 @@ static inline void set_feature(CPUUniCore32State *env, int feature)
env->features |= feature;
}
-struct uc32_cpu_t {
- uint32_t id;
- const char *name;
-};
-
-static const struct uc32_cpu_t uc32_cpu_names[] = {
- { UC32_CPUID_UCV2, "UniCore-II"},
- { UC32_CPUID_ANY, "any"},
- { 0, NULL}
-};
-
-/* return 0 if not found */
-static uint32_t uc32_cpu_find_by_name(const char *name)
-{
- int i;
- uint32_t id;
-
- id = 0;
- for (i = 0; uc32_cpu_names[i].name; i++) {
- if (strcmp(name, uc32_cpu_names[i].name) == 0) {
- id = uc32_cpu_names[i].id;
- break;
- }
- }
- return id;
-}
-
CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
{
+ UniCore32CPU *cpu;
CPUUniCore32State *env;
uint32_t id;
static int inited = 1;
- env = g_malloc0(sizeof(CPUUniCore32State));
- cpu_exec_init(env);
+ if (object_class_by_name(cpu_model) == NULL) {
+ return NULL;
+ }
+ cpu = UNICORE32_CPU(object_new(cpu_model));
+ env = &cpu->env;
- id = uc32_cpu_find_by_name(cpu_model);
+ id = env->cp0.c0_cpuid;
switch (id) {
case UC32_CPUID_UCV2:
set_feature(env, UC32_HWCAP_CMOV);
@@ -72,17 +49,11 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
cpu_abort(env, "Bad CPU ID: %x\n", id);
}
- env->cpu_model_str = cpu_model;
- env->cp0.c0_cpuid = id;
- env->uncached_asr = ASR_MODE_USER;
- env->regs[31] = 0;
-
if (inited) {
inited = 0;
uc32_translate_init();
}
- tlb_flush(env, 1);
qemu_init_vcpu(env);
return env;
}
commit c3a8baa90d98edcf290bfda6850615368738a17c
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Mar 15 15:02:14 2012 +0100
target-unicore32: License future contributions under GPLv2+
This is to limit relicensing obstacles to the pending IBM investigation.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Guan Xuetao <gxt at mprc.pku.edu.cn>
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 6af492d..18a9cbb 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -4,6 +4,9 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
+ *
+ * Contributions from 2012-04-01 on are considered under GPL version 2,
+ * or (at your option) any later version.
*/
#include "cpu.h"
commit 2b3bc6c0f56968631c4d92b7e06ec969ed0700bb
Author: Andreas Färber <afaerber at suse.de>
Date: Tue Mar 13 16:48:19 2012 +0100
target-unicore32: Relicense to GPLv2+
Adopt the license text suggested by Guan Xue-tao (with a minor
simplification) for all target-unicore/ files except helper.c.
To helper.c Anthony Liguori contributed a qemu_malloc() -> g_malloc()
conversion, still pending IBM relicensing approval, so that remains
GPLv2 for now.
By relicensing all possible parts now, we avoid having to formally
relicense new, e.g., QOM code.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Guan Xuetao <gxt at mprc.pku.edu.cn>
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Dor Laor <dlaor at redhat.com>
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index a3f8589..8ec0d2f 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -5,7 +5,8 @@
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
*/
#ifndef __CPU_UC32_H__
#define __CPU_UC32_H__
diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h
index 615de2a..5a3b8a4 100644
--- a/target-unicore32/helper.h
+++ b/target-unicore32/helper.h
@@ -3,7 +3,8 @@
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
*/
#include "def-helper.h"
diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c
index 638a020..b954c30 100644
--- a/target-unicore32/op_helper.c
+++ b/target-unicore32/op_helper.c
@@ -5,7 +5,8 @@
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
*/
#include "cpu.h"
#include "dyngen-exec.h"
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index 3b3ba16..9793d14 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -5,7 +5,8 @@
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
*/
#include <stdarg.h>
#include <stdlib.h>
commit a6ea7b4c5e44ba6965accd3ada3a9c02fead042d
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Mar 14 00:45:43 2012 +0100
MAINTAINERS: Add entry for UniCore32
Signed-off-by: Andreas Färber <afaerber at suse.de>
Acked-by: Guan Xuetao <gxt at mprc.pku.edu.cn>
diff --git a/MAINTAINERS b/MAINTAINERS
index f83d07c..922945c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -112,6 +112,11 @@ M: Blue Swirl <blauwirbel at gmail.com>
S: Maintained
F: target-sparc/
+UniCore32
+M: Guan Xuetao <gxt at mprc.pku.edu.cn>
+S: Maintained
+F: target-unicore32/
+
X86
M: qemu-devel at nongnu.org
S: Odd Fixes
commit 040b66f3f97ba9299c0be9da025a9197db654198
Merge: cbd5979... f638f0d...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Thu Mar 29 13:32:41 2012 -0500
Merge remote-tracking branch 'origin/master' into staging
* origin/master:
qemu tcg: Remove one entry of INDEX_op_ld_i64 from ppc_op_defs
commit dec9c2d4306d7b4f8ffff482ac42dc468ed2a61d
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Mar 29 04:50:31 2012 +0000
target-arm: Minimalistic CPU QOM'ification
Introduce only one non-abstract type TYPE_ARM_CPU and do not touch
cp15 registers to not interfere with Peter's ongoing remodelling.
Embed CPUARMState as first (additional) field of ARMCPU.
Let CPUClass::reset() call cpu_state_reset() for now.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/Makefile.target b/Makefile.target
index 44b2e83..6e8b997 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -92,6 +92,7 @@ endif
libobj-$(TARGET_SPARC64) += vis_helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
+libobj-$(TARGET_ARM) += cpu.o
ifeq ($(TARGET_BASE_ARCH), sparc)
libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
libobj-y += cpu_init.o
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
new file mode 100644
index 0000000..42d2a6b
--- /dev/null
+++ b/target-arm/cpu-qom.h
@@ -0,0 +1,71 @@
+/*
+ * QEMU ARM CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ */
+#ifndef QEMU_ARM_CPU_QOM_H
+#define QEMU_ARM_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_ARM_CPU "arm-cpu"
+
+#define ARM_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(ARMCPUClass, (klass), TYPE_ARM_CPU)
+#define ARM_CPU(obj) \
+ OBJECT_CHECK(ARMCPU, (obj), TYPE_ARM_CPU)
+#define ARM_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(ARMCPUClass, (obj), TYPE_ARM_CPU)
+
+/**
+ * ARMCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An ARM CPU model.
+ */
+typedef struct ARMCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} ARMCPUClass;
+
+/**
+ * ARMCPU:
+ * @env: #CPUARMState
+ *
+ * An ARM CPU core.
+ */
+typedef struct ARMCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUARMState env;
+} ARMCPU;
+
+static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
+{
+ return ARM_CPU(container_of(env, ARMCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e))
+
+
+#endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
new file mode 100644
index 0000000..c3ed45b
--- /dev/null
+++ b/target-arm/cpu.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU ARM CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+
+/* CPUClass::reset() */
+static void arm_cpu_reset(CPUState *s)
+{
+ ARMCPU *cpu = ARM_CPU(s);
+ ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
+
+ acc->parent_reset(s);
+
+ /* TODO Inline the current contents of cpu_state_reset(),
+ once cpu_reset_model_id() is eliminated. */
+ cpu_state_reset(&cpu->env);
+}
+
+static void arm_cpu_class_init(ObjectClass *oc, void *data)
+{
+ ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(acc);
+
+ acc->parent_reset = cc->reset;
+ cc->reset = arm_cpu_reset;
+}
+
+static const TypeInfo arm_cpu_type_info = {
+ .name = TYPE_ARM_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(ARMCPU),
+ .abstract = false,
+ .class_size = sizeof(ARMCPUClass),
+ .class_init = arm_cpu_class_init,
+};
+
+static void arm_cpu_register_types(void)
+{
+ type_register_static(&arm_cpu_type_info);
+}
+
+type_init(arm_cpu_register_types)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 69ef142..a68df61 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -475,6 +475,7 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
#endif
#include "cpu-all.h"
+#include "cpu-qom.h"
/* Bit usage in the TB flags field: */
#define ARM_TBFLAG_THUMB_SHIFT 0
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 1ce8105..dd8e306 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -278,6 +278,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
}
}
+/* TODO Move contents into arm_cpu_reset() in cpu.c,
+ * once cpu_reset_model_id() is eliminated,
+ * and then forward to cpu_reset() here.
+ */
void cpu_state_reset(CPUARMState *env)
{
uint32_t id;
@@ -400,6 +404,7 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
CPUARMState *cpu_arm_init(const char *cpu_model)
{
+ ARMCPU *cpu;
CPUARMState *env;
uint32_t id;
static int inited = 0;
@@ -407,7 +412,8 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
id = cpu_arm_find_by_name(cpu_model);
if (id == 0)
return NULL;
- env = g_malloc0(sizeof(CPUARMState));
+ cpu = ARM_CPU(object_new(TYPE_ARM_CPU));
+ env = &cpu->env;
cpu_exec_init(env);
if (tcg_enabled() && !inited) {
inited = 1;
commit 0bcd08b3522e4feffe3111e7c8145f62d32cc1fb
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Mar 29 04:50:30 2012 +0000
target-arm: Drop cpu_arm_close()
It's unused, so no need to QOM'ify it later.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 26c114b..69ef142 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -238,7 +238,6 @@ typedef struct CPUARMState {
CPUARMState *cpu_arm_init(const char *cpu_model);
void arm_translate_init(void);
int cpu_arm_exec(CPUARMState *s);
-void cpu_arm_close(CPUARMState *s);
void do_interrupt(CPUARMState *);
void switch_mode(CPUARMState *, int);
uint32_t do_arm_semihosting(CPUARMState *env);
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 1314f23..1ce8105 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -493,11 +493,6 @@ static uint32_t cpu_arm_find_by_name(const char *name)
return id;
}
-void cpu_arm_close(CPUARMState *env)
-{
- g_free(env);
-}
-
static int bad_mode_switch(CPUARMState *env, int mode)
{
/* Return true if it is not valid for us to switch to
commit f638f0d3ae214d995cdd94578195700cda24597b
Author: Li Zhang <zhlcindy at linux.vnet.ibm.com>
Date: Thu Mar 29 14:29:02 2012 +1100
qemu tcg: Remove one entry of INDEX_op_ld_i64 from ppc_op_defs
There two entries of INDEX_op_ld_i64 in the ppc_op_defs. That causes an
assertion failure in tcg_add_target_add_op_defs() when --enable-debug is
used on a ppc64 backend (that's ppc64 host, not target).
Signed-off-by: Li Zhang <zhlcindy at linux.vnet.ibm.com>
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index 409a1ac..f2ad9e3 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -1656,7 +1656,6 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_ld16s_i64, { "r", "r" } },
{ INDEX_op_ld32u_i64, { "r", "r" } },
{ INDEX_op_ld32s_i64, { "r", "r" } },
- { INDEX_op_ld_i64, { "r", "r" } },
{ INDEX_op_add_i32, { "r", "r", "ri" } },
{ INDEX_op_mul_i32, { "r", "r", "ri" } },
commit 56688961634a2d05fb5841a149bb5c1a17239e4c
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Wed Mar 28 21:03:42 2012 +0200
w32/slirp: Undefine error constants before their redefinition
Less warnings for your console.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 2098b20..46bfe46 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -15,6 +15,12 @@ typedef char *caddr_t;
# include <sys/timeb.h>
# include <iphlpapi.h>
+# undef EWOULDBLOCK
+# undef EINPROGRESS
+# undef ENOTCONN
+# undef EHOSTUNREACH
+# undef ENETUNREACH
+# undef ECONNREFUSED
# define EWOULDBLOCK WSAEWOULDBLOCK
# define EINPROGRESS WSAEINPROGRESS
# define ENOTCONN WSAENOTCONN
commit 1c5970a8b8ed79334e8ab303fec7287442538c3c
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 01:02:52 2012 +0100
slirp: use socket_set_nonblock
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/slirp/misc.c b/slirp/misc.c
index 0308a62..0bee864 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -215,7 +215,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
opt = 1;
setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
- fd_nonblock(so->s);
+ socket_set_nonblock(so->s);
/* Append the telnet options now */
if (so->so_m != NULL && do_pty == 1) {
@@ -267,50 +267,6 @@ u_sleep(int usec)
select(0, &fdset, &fdset, &fdset, &t);
}
-/*
- * Set fd blocking and non-blocking
- */
-
-void
-fd_nonblock(int fd)
-{
-#ifdef FIONBIO
-#ifdef _WIN32
- unsigned long opt = 1;
-#else
- int opt = 1;
-#endif
-
- ioctlsocket(fd, FIONBIO, &opt);
-#else
- int opt;
-
- opt = fcntl(fd, F_GETFL, 0);
- opt |= O_NONBLOCK;
- fcntl(fd, F_SETFL, opt);
-#endif
-}
-
-void
-fd_block(int fd)
-{
-#ifdef FIONBIO
-#ifdef _WIN32
- unsigned long opt = 0;
-#else
- int opt = 0;
-#endif
-
- ioctlsocket(fd, FIONBIO, &opt);
-#else
- int opt;
-
- opt = fcntl(fd, F_GETFL, 0);
- opt &= ~O_NONBLOCK;
- fcntl(fd, F_SETFL, opt);
-#endif
-}
-
void slirp_connection_info(Slirp *slirp, Monitor *mon)
{
const char * const tcpstates[] = {
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 6f6585a..0a545c4 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -336,7 +336,7 @@ int tcp_fconnect(struct socket *so)
int opt, s=so->s;
struct sockaddr_in addr;
- fd_nonblock(s);
+ socket_set_nonblock(s);
opt = 1;
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
opt = 1;
@@ -424,7 +424,7 @@ tcp_connect(struct socket *inso)
tcp_close(sototcpcb(so)); /* This will sofree() as well */
return;
}
- fd_nonblock(s);
+ socket_set_nonblock(s);
opt = 1;
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
opt = 1;
commit b72210568ef0c0fb141a01cffb71a09c4efa0364
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 01:02:51 2012 +0100
slirp: clean up conflicts with system headers
Right now, slirp/slirp.h cannot include some system headers and,
indirectly, qemu_socket.h. Clean this up, and remove a duplicate
prototype that was introduced because of that.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 5033ee3..2098b20 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -88,10 +88,6 @@ void *malloc(size_t arg);
void free(void *ptr);
#endif
-#ifndef HAVE_INET_ATON
-int inet_aton(const char *cp, struct in_addr *ia);
-#endif
-
#include <fcntl.h>
#ifndef NO_UNIX_SOCKETS
#include <sys/un.h>
@@ -144,6 +140,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
#include "debug.h"
#include "qemu-queue.h"
+#include "qemu_socket.h"
#include "libslirp.h"
#include "ip.h"
@@ -167,9 +164,6 @@ int inet_aton(const char *cp, struct in_addr *ia);
#include "bootp.h"
#include "tftp.h"
-/* osdep.c */
-int qemu_socket(int domain, int type, int protocol);
-
#define ETH_ALEN 6
#define ETH_HLEN 14
diff --git a/slirp/tcp.h b/slirp/tcp.h
index b3817cb..8299603 100644
--- a/slirp/tcp.h
+++ b/slirp/tcp.h
@@ -45,6 +45,7 @@ typedef uint32_t tcp_seq;
* TCP header.
* Per RFC 793, September, 1981.
*/
+#define tcphdr slirp_tcphdr
struct tcphdr {
uint16_t th_sport; /* source port */
uint16_t th_dport; /* destination port */
@@ -58,12 +59,6 @@ struct tcphdr {
th_off:4; /* data offset */
#endif
uint8_t th_flags;
-#define TH_FIN 0x01
-#define TH_SYN 0x02
-#define TH_RST 0x04
-#define TH_PUSH 0x08
-#define TH_ACK 0x10
-#define TH_URG 0x20
uint16_t th_win; /* window */
uint16_t th_sum; /* checksum */
uint16_t th_urp; /* urgent pointer */
@@ -71,6 +66,16 @@ struct tcphdr {
#include "tcp_var.h"
+#ifndef TH_FIN
+#define TH_FIN 0x01
+#define TH_SYN 0x02
+#define TH_RST 0x04
+#define TH_PUSH 0x08
+#define TH_ACK 0x10
+#define TH_URG 0x20
+#endif
+
+#ifndef TCPOPT_EOL
#define TCPOPT_EOL 0
#define TCPOPT_NOP 1
#define TCPOPT_MAXSEG 2
@@ -86,6 +91,7 @@ struct tcphdr {
#define TCPOPT_TSTAMP_HDR \
(TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
+#endif
/*
* Default maximum segment size for TCP.
@@ -95,10 +101,13 @@ struct tcphdr {
*
* We make this 1460 because we only care about Ethernet in the qemu context.
*/
+#undef TCP_MSS
#define TCP_MSS 1460
+#undef TCP_MAXWIN
#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
+#undef TCP_MAX_WINSHIFT
#define TCP_MAX_WINSHIFT 14 /* maximum window shift */
/*
commit cbd5979bb2ca8609ef19ebdfdc46043c46f0b42e
Merge: 49e00ba... d56de07...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Mar 28 12:46:39 2012 -0500
Merge remote-tracking branch 'sstabellini/disk_io' into staging
* sstabellini/disk_io:
xen_disk: when using AIO flush after the operation is completed
xen_disk: open disk with BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO
commit 49e00ba9698469b5eccec947050216192d9a9e34
Merge: c76d1a9... 7429f2e...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Mar 28 12:46:11 2012 -0500
Merge remote-tracking branch 'sstabellini/xen-fixes' into staging
* sstabellini/xen-fixes:
xen_disk: detach the blkdev before bdrv_delete
xen_console: ignore console disconnect events from console/0
commit c76d1a9b3f367754966c326d81ff8566798b473a
Merge: 0a5a4e0... 1829851...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Mar 28 12:45:22 2012 -0500
Merge remote-tracking branch 'qmp/queue/qmp' into staging
* qmp/queue/qmp:
qmp: document strict parsing
qmp: parse commands in strict mode
qmp: add and use q type specifier
qapi: add strict mode to input visitor
qapi: place outermost object on qiv stack
qapi: untangle next_list
qapi: allow freeing partially-allocated objects
qapi: shortcut visits on errors
qapi: fix memory leak on error
qapi: fail hard on stack imbalance
qapi: add a test case for type errors
qapi: add struct-errors test case to test-qmp-output-visitor
qapi: fix double free in qmp_output_visitor_cleanup()
commit 0a5a4e0568d4cc981457a2d1e7f86923eeff94ed
Merge: 1658dd3... 6f06f17...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Mar 28 12:44:04 2012 -0500
Merge remote-tracking branch 'alon/libcacard' into staging
* alon/libcacard:
libcacard/vcard_emul_nss: add warning for old coolkey
libcacard/vcard_emul_nss: handle no readers at startup
libcacard/vcard_emul_nss: don't stop thread when there are no slots
commit 1658dd32408c75e850b55ab0ff70d5cc402674d5
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sun Mar 18 11:31:23 2012 +0000
sparc: pass page aligned addresses to tlb_set_page
Mask incoming page address early so that resolved addresses
are page aligned. Remove further address masking.
Tested-by: Artyom Tarasenko <atar4qemu at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
index 11fb9f5..cb73c44 100644
--- a/target-sparc/mmu_helper.c
+++ b/target-sparc/mmu_helper.c
@@ -150,18 +150,17 @@ static int get_physical_address(CPUSPARCState *env, target_phys_addr_t *physical
case 3: /* Reserved */
return (3 << 8) | (4 << 2);
case 2: /* L3 PTE */
- page_offset = (address & TARGET_PAGE_MASK) &
- (TARGET_PAGE_SIZE - 1);
+ page_offset = 0;
}
*page_size = TARGET_PAGE_SIZE;
break;
case 2: /* L2 PTE */
- page_offset = address & 0x3ffff;
+ page_offset = address & 0x3f000;
*page_size = 0x40000;
}
break;
case 2: /* L1 PTE */
- page_offset = address & 0xffffff;
+ page_offset = address & 0xfff000;
*page_size = 0x1000000;
}
}
@@ -206,11 +205,11 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
target_ulong page_size;
int error_code = 0, prot, access_index;
+ address &= TARGET_PAGE_MASK;
error_code = get_physical_address(env, &paddr, &prot, &access_index,
address, rw, mmu_idx, &page_size);
+ vaddr = address;
if (error_code == 0) {
- vaddr = address & TARGET_PAGE_MASK;
- paddr &= TARGET_PAGE_MASK;
#ifdef DEBUG_MMU
printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
TARGET_FMT_lx "\n", address, paddr, vaddr);
@@ -230,7 +229,6 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
permissions. If no mapping is available, redirect accesses to
neverland. Fake/overridden mappings will be flushed when
switching to normal mode. */
- vaddr = address & TARGET_PAGE_MASK;
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
@@ -704,17 +702,16 @@ static int get_physical_address(CPUSPARCState *env, target_phys_addr_t *physical
int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
int mmu_idx)
{
- target_ulong virt_addr, vaddr;
+ target_ulong vaddr;
target_phys_addr_t paddr;
target_ulong page_size;
int error_code = 0, prot, access_index;
+ address &= TARGET_PAGE_MASK;
error_code = get_physical_address(env, &paddr, &prot, &access_index,
address, rw, mmu_idx, &page_size);
if (error_code == 0) {
- virt_addr = address & TARGET_PAGE_MASK;
- vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
- (TARGET_PAGE_SIZE - 1));
+ vaddr = address;
trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
env->dmmu.mmu_primary_context,
commit 7429f2e1981c6cc77a853e2e88654001bdddd461
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date: Tue Mar 27 16:03:07 2012 +0000
xen_disk: detach the blkdev before bdrv_delete
We need to detach the blkdev from the BlockDriverState before calling
bdrv_delete.
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 68fa36a..bf06fc1 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -726,6 +726,7 @@ static void blk_disconnect(struct XenDevice *xendev)
if (!blkdev->dinfo) {
/* close/delete only if we created it ourself */
bdrv_close(blkdev->bs);
+ bdrv_detach_dev(blkdev->bs, blkdev);
bdrv_delete(blkdev->bs);
}
blkdev->bs = NULL;
commit 028c85f0fffe5d4fdd435e06af4188397acf1cb6
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date: Tue Mar 27 16:02:21 2012 +0000
xen_console: ignore console disconnect events from console/0
The first console has a different location compared to other PV devices
(console, rather than device/console/0) and doesn't obey the xenstore
state protocol. We already special case the first console in con_init
and con_initialise, we should also do it in con_disconnect.
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/hw/xen_console.c b/hw/xen_console.c
index edcb31c..3794b19 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -248,6 +248,9 @@ static void con_disconnect(struct XenDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+ if (!xendev->dev) {
+ return;
+ }
if (con->chr)
qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
xen_be_unbind_evtchn(&con->xendev);
commit 1829851cfee10e196abec50325d828de182fd356
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 22:39:39 2012 +0100
qmp: document strict parsing
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
index 9d30a8c..1ba916c 100644
--- a/QMP/qmp-spec.txt
+++ b/QMP/qmp-spec.txt
@@ -209,13 +209,27 @@ incompatible way are disabled by default and will be advertised by the
capabilities array (section '2.2 Server Greeting'). Thus, Clients can check
that array and enable the capabilities they support.
-Additionally, Clients must not assume any particular:
-
-- Size of json-objects or length of json-arrays
+The QMP Server performs a type check on the arguments to a command. It
+generates an error if a value does not have the expected type for its
+key, or if it does not understand a key that the Client included. The
+strictness of the Server catches wrong assumptions of Clients about
+the Server's schema. Clients can assume that, when such validation
+errors occur, they will be reported before the command generated any
+side effect.
+
+However, Clients must not assume any particular:
+
+- Length of json-arrays
+- Size of json-objects; in particular, future versions of QEMU may add
+ new keys and Clients should be able to ignore them.
- Order of json-object members or json-array elements
- Amount of errors generated by a command, that is, new errors can be added
to any existing command in newer versions of the Server
+Of course, the Server does guarantee to send valid JSON. But apart from
+this, a Client should be "conservative in what they send, and liberal in
+what they accept".
+
6. Downstream extension of QMP
------------------------------
commit 6d36d7dc2b1eeded7627745989fa6e20cb39eefd
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:12 2012 +0100
qmp: parse commands in strict mode
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-off-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 30a24d2..0b4f0a0 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -140,7 +140,7 @@ v = qapi_dealloc_get_visitor(md);
''')
else:
ret += mcgen('''
-mi = qmp_input_visitor_new(%(obj)s);
+mi = qmp_input_visitor_new_strict(%(obj)s);
v = qmp_input_get_visitor(mi);
''',
obj=obj)
commit b9f8978cc428559c684df88ed69b709e33ba17dc
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:11 2012 +0100
qmp: add and use q type specifier
"O" is being used by the transaction and qom-set commands to mean "any
QObject", but it really means "do not validate the argument list".
Add a new specifier with the correct meaning.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/monitor.c b/monitor.c
index 2ff1e0b..8946a10 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4157,6 +4157,9 @@ static int check_client_args_type(const QDict *client_args,
case 'O':
assert(flags & QMP_ACCEPT_UNKNOWNS);
break;
+ case 'q':
+ /* Any QObject can be passed. */
+ break;
case '/':
case '.':
/*
diff --git a/qmp-commands.hx b/qmp-commands.hx
index c626ba8..9447871 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -708,7 +708,7 @@ EQMP
},
{
.name = "transaction",
- .args_type = "actions:O",
+ .args_type = "actions:q",
.mhandler.cmd_new = qmp_marshal_input_transaction,
},
@@ -2125,7 +2125,7 @@ EQMP
{
.name = "qom-set",
- .args_type = "path:s,property:s,opts:O",
+ .args_type = "path:s,property:s,value:q",
.mhandler.cmd_new = qmp_qom_set,
},
commit e38ac9621c8ab51880b9e6e833a125342d6b46b2
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:10 2012 +0100
qapi: add strict mode to input visitor
While QMP in general is designed so that it is possible to ignore
unknown arguments, in the case of the QMP server it is better to
reject them to detect bad clients. In fact, we're already doing
this at the top level in the argument checker. To extend this to
complex structures, add a mode to the input visitor where it checks
for unvisited keys and raises an error if it finds one.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index 5765e76..74386b9 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -24,6 +24,7 @@ typedef struct StackObject
{
QObject *obj;
const QListEntry *entry;
+ GHashTable *h;
} StackObject;
struct QmpInputVisitor
@@ -31,6 +32,7 @@ struct QmpInputVisitor
Visitor visitor;
StackObject stack[QIV_STACK_SIZE];
int nb_stack;
+ bool strict;
};
static QmpInputVisitor *to_qiv(Visitor *v)
@@ -45,6 +47,9 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
if (qobj) {
if (name && qobject_type(qobj) == QTYPE_QDICT) {
+ if (qiv->stack[qiv->nb_stack - 1].h) {
+ g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name);
+ }
return qdict_get(qobject_to_qdict(qobj), name);
} else if (qiv->stack[qiv->nb_stack - 1].entry) {
return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
@@ -54,20 +59,47 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
return qobj;
}
+static void qdict_add_key(const char *key, QObject *obj, void *opaque)
+{
+ GHashTable *h = opaque;
+ g_hash_table_insert(h, (gpointer) key, NULL);
+}
+
static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
{
- qiv->stack[qiv->nb_stack].obj = obj;
- qiv->stack[qiv->nb_stack].entry = NULL;
- qiv->nb_stack++;
+ GHashTable *h;
if (qiv->nb_stack >= QIV_STACK_SIZE) {
error_set(errp, QERR_BUFFER_OVERRUN);
return;
}
+
+ qiv->stack[qiv->nb_stack].obj = obj;
+ qiv->stack[qiv->nb_stack].entry = NULL;
+ qiv->stack[qiv->nb_stack].h = NULL;
+
+ if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
+ h = g_hash_table_new(g_str_hash, g_str_equal);
+ qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
+ qiv->stack[qiv->nb_stack].h = h;
+ }
+
+ qiv->nb_stack++;
}
static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
{
+ GHashTableIter iter;
+ gpointer key;
+
+ if (qiv->strict && qiv->stack[qiv->nb_stack - 1].h) {
+ g_hash_table_iter_init(&iter, qiv->stack[qiv->nb_stack - 1].h);
+ if (g_hash_table_iter_next(&iter, &key, NULL)) {
+ error_set(errp, QERR_QMP_EXTRA_MEMBER, (char *) key);
+ }
+ g_hash_table_unref(qiv->stack[qiv->nb_stack - 1].h);
+ }
+
assert(qiv->nb_stack > 0);
qiv->nb_stack--;
}
@@ -262,3 +294,13 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
return v;
}
+
+QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj)
+{
+ QmpInputVisitor *v;
+
+ v = qmp_input_visitor_new(obj);
+ v->strict = true;
+
+ return v;
+}
diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
index 3f798f0..e0a48a5 100644
--- a/qapi/qmp-input-visitor.h
+++ b/qapi/qmp-input-visitor.h
@@ -20,6 +20,8 @@
typedef struct QmpInputVisitor QmpInputVisitor;
QmpInputVisitor *qmp_input_visitor_new(QObject *obj);
+QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj);
+
void qmp_input_visitor_cleanup(QmpInputVisitor *v);
Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
diff --git a/test-qmp-input-strict.c b/test-qmp-input-strict.c
new file mode 100644
index 0000000..f6df8cb
--- /dev/null
+++ b/test-qmp-input-strict.c
@@ -0,0 +1,234 @@
+/*
+ * QMP Input Visitor unit-tests (strict mode).
+ *
+ * Copyright (C) 2011-2012 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino at redhat.com>
+ * Paolo Bonzini <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <stdarg.h>
+
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestInputVisitorData {
+ QObject *obj;
+ QmpInputVisitor *qiv;
+} TestInputVisitorData;
+
+static void validate_teardown(TestInputVisitorData *data,
+ const void *unused)
+{
+ qobject_decref(data->obj);
+ data->obj = NULL;
+
+ if (data->qiv) {
+ qmp_input_visitor_cleanup(data->qiv);
+ data->qiv = NULL;
+ }
+}
+
+/* This is provided instead of a test setup function so that the JSON
+ string used by the tests are kept in the test functions (and not
+ int main()) */
+static GCC_FMT_ATTR(2, 3)
+Visitor *validate_test_init(TestInputVisitorData *data,
+ const char *json_string, ...)
+{
+ Visitor *v;
+ va_list ap;
+
+ va_start(ap, json_string);
+ data->obj = qobject_from_jsonv(json_string, &ap);
+ va_end(ap);
+
+ g_assert(data->obj != NULL);
+
+ data->qiv = qmp_input_visitor_new_strict(data->obj);
+ g_assert(data->qiv != NULL);
+
+ v = qmp_input_get_visitor(data->qiv);
+ g_assert(v != NULL);
+
+ return v;
+}
+
+typedef struct TestStruct
+{
+ int64_t integer;
+ bool boolean;
+ char *string;
+} TestStruct;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
+ const char *name, Error **errp)
+{
+ visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
+ errp);
+
+ visit_type_int(v, &(*obj)->integer, "integer", errp);
+ visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+ visit_type_str(v, &(*obj)->string, "string", errp);
+
+ visit_end_struct(v, errp);
+}
+
+static void test_validate_struct(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_free(p->string);
+ g_free(p);
+}
+
+static void test_validate_struct_nested(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNested *udp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
+
+ visit_type_UserDefNested(v, &udp, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefNested(udp);
+}
+
+static void test_validate_list(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *head = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
+
+ visit_type_UserDefOneList(v, &head, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefOneList(head);
+}
+
+static void test_validate_union(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefUnion *tmp = NULL;
+ Visitor *v;
+ Error *errp = NULL;
+
+ v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
+
+ visit_type_UserDefUnion(v, &tmp, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefUnion(tmp);
+}
+
+static void test_validate_fail_struct(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ if (p) {
+ g_free(p->string);
+ }
+ g_free(p);
+}
+
+static void test_validate_fail_struct_nested(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNested *udp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}");
+
+ visit_type_UserDefNested(v, &udp, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefNested(udp);
+}
+
+static void test_validate_fail_list(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *head = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]");
+
+ visit_type_UserDefOneList(v, &head, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefOneList(head);
+}
+
+static void test_validate_fail_union(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefUnion *tmp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 }, 'extra': 'yyy' }");
+
+ visit_type_UserDefUnion(v, &tmp, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefUnion(tmp);
+}
+
+static void validate_test_add(const char *testpath,
+ TestInputVisitorData *data,
+ void (*test_func)(TestInputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
+ validate_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ TestInputVisitorData testdata;
+
+ g_test_init(&argc, &argv, NULL);
+
+ validate_test_add("/visitor/input-strict/pass/struct",
+ &testdata, test_validate_struct);
+ validate_test_add("/visitor/input-strict/pass/struct-nested",
+ &testdata, test_validate_struct_nested);
+ validate_test_add("/visitor/input-strict/pass/list",
+ &testdata, test_validate_list);
+ validate_test_add("/visitor/input-strict/pass/union",
+ &testdata, test_validate_union);
+ validate_test_add("/visitor/input-strict/fail/struct",
+ &testdata, test_validate_fail_struct);
+ validate_test_add("/visitor/input-strict/fail/struct-nested",
+ &testdata, test_validate_fail_struct_nested);
+ validate_test_add("/visitor/input-strict/fail/list",
+ &testdata, test_validate_fail_list);
+ validate_test_add("/visitor/input-strict/fail/union",
+ &testdata, test_validate_fail_union);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/Makefile b/tests/Makefile
index 94ea342..2a2fff7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -16,7 +16,7 @@ check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y)
check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
-test-qmp-input-visitor.o test-qmp-output-visitor.o \
+test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-input-strict.o \
test-string-input-visitor.o test-string-output-visitor.o \
test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
@@ -37,6 +37,9 @@ test-string-output-visitor: test-string-output-visitor.o $(qobject-obj-y) $(qapi
test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+test-qmp-input-strict.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
+test-qmp-input-strict: test-qmp-input-strict.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
commit 4faaec6acf7f18b39c362edb9f6aa5658aab8b85
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:09 2012 +0100
qapi: place outermost object on qiv stack
This is a slight change in the implementation of QMPInputVisitor
that helps when adding strict mode.
Const QObjects cannot be inc/decref-ed, and that's why QMPInputVisitor
relies heavily on weak references to inner objects. I'm not removing
the weak references now, but since refcount+const is a lost battle in C
(C++ has "mutable") I think removing const is fine in this case.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index 413e333..5765e76 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -22,14 +22,13 @@
typedef struct StackObject
{
- const QObject *obj;
- const QListEntry *entry;
+ QObject *obj;
+ const QListEntry *entry;
} StackObject;
struct QmpInputVisitor
{
Visitor visitor;
- QObject *obj;
StackObject stack[QIV_STACK_SIZE];
int nb_stack;
};
@@ -39,21 +38,15 @@ static QmpInputVisitor *to_qiv(Visitor *v)
return container_of(v, QmpInputVisitor, visitor);
}
-static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
- const char *name)
+static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
+ const char *name)
{
- const QObject *qobj;
-
- if (qiv->nb_stack == 0) {
- qobj = qiv->obj;
- } else {
- qobj = qiv->stack[qiv->nb_stack - 1].obj;
- }
+ QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj;
if (qobj) {
if (name && qobject_type(qobj) == QTYPE_QDICT) {
return qdict_get(qobject_to_qdict(qobj), name);
- } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
+ } else if (qiv->stack[qiv->nb_stack - 1].entry) {
return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
}
}
@@ -61,7 +54,7 @@ static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
return qobj;
}
-static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
+static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
{
qiv->stack[qiv->nb_stack].obj = obj;
qiv->stack[qiv->nb_stack].entry = NULL;
@@ -83,7 +76,7 @@ static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
const char *name, size_t size, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
Error *err = NULL;
if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
@@ -113,7 +106,7 @@ static void qmp_input_end_struct(Visitor *v, Error **errp)
static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -165,7 +158,7 @@ static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -180,7 +173,7 @@ static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -195,7 +188,7 @@ static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -210,7 +203,7 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -225,7 +218,7 @@ static void qmp_input_start_optional(Visitor *v, bool *present,
const char *name, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj) {
*present = false;
@@ -242,7 +235,7 @@ Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
void qmp_input_visitor_cleanup(QmpInputVisitor *v)
{
- qobject_decref(v->obj);
+ qobject_decref(v->stack[0].obj);
g_free(v);
}
@@ -264,8 +257,8 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
v->visitor.type_number = qmp_input_type_number;
v->visitor.start_optional = qmp_input_start_optional;
- v->obj = obj;
- qobject_incref(v->obj);
+ qmp_input_push(v, obj, NULL);
+ qobject_incref(obj);
return v;
}
commit 3a86a0fa76b5103a122b6e817b3827b2837f4956
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 22:38:40 2012 +0100
qapi: untangle next_list
Right now, the semantics of next_list are complicated. The caller must:
* call start_list
* call next_list for each element *including the first*
* on the first call to next_list, the second argument should point to
NULL and the result is the head of the list. On subsequent calls,
the second argument should point to the last node (last result of
next_list) and next_list itself tacks the element at the tail of the
list.
This works for both input and output visitor, but having the visitor
write memory when it is only reading the list is ugly. Plus, relying
on *list to detect the first call is tricky and undocumented.
We can initialize so->entry in next_list instead of start_list, leaving
it NULL in start_list. This way next_list sees clearly whether it is
on the first call---as a bonus, it discriminates the cases based on
internal state of the visitor rather than external state. We can
also pull the assignment of the list head from generated code up to
next_list.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 5831e37..ad11767 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -194,11 +194,11 @@ Example:
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
{
- GenericList *i;
+ GenericList *i, **prev = (GenericList **)obj;
visit_start_list(m, name, errp);
- for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+ for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
UserDefOneList *native_i = (UserDefOneList *)i;
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
}
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index ef9288f..413e333 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -64,9 +64,7 @@ static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
{
qiv->stack[qiv->nb_stack].obj = obj;
- if (qobject_type(obj) == QTYPE_QLIST) {
- qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
- }
+ qiv->stack[qiv->nb_stack].entry = NULL;
qiv->nb_stack++;
if (qiv->nb_stack >= QIV_STACK_SIZE) {
@@ -132,18 +130,24 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
QmpInputVisitor *qiv = to_qiv(v);
GenericList *entry;
StackObject *so = &qiv->stack[qiv->nb_stack - 1];
+ bool first;
+
+ if (so->entry == NULL) {
+ so->entry = qlist_first(qobject_to_qlist(so->obj));
+ first = true;
+ } else {
+ so->entry = qlist_next(so->entry);
+ first = false;
+ }
if (so->entry == NULL) {
return NULL;
}
entry = g_malloc0(sizeof(*entry));
- if (*list) {
- so->entry = qlist_next(so->entry);
- if (so->entry == NULL) {
- g_free(entry);
- return NULL;
- }
+ if (first) {
+ *list = entry;
+ } else {
(*list)->next = entry;
}
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 31d50a6..8d4e94a 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -86,14 +86,14 @@ def generate_visit_list(name, members):
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
{
- GenericList *i, **head = (GenericList **)obj;
+ GenericList *i, **prev = (GenericList **)obj;
if (error_is_set(errp)) {
return;
}
visit_start_list(m, name, errp);
- for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) {
+ for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
%(name)sList *native_i = (%(name)sList *)i;
visit_type_%(name)s(m, &native_i->value, NULL, errp);
}
commit 69b50071d8dc1b4e06724bb73cda8e2f10fe30c7
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:07 2012 +0100
qapi: allow freeing partially-allocated objects
Objects going through the dealloc visitor can be only partially allocated.
Detect the situation and avoid a segfault. This also helps with the
input visitor, when there are errors.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 4297621..31d50a6 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -65,6 +65,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
return;
}
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), errp);
+ if (obj && !*obj) {
+ goto end;
+ }
''',
name=name)
push_indent()
@@ -72,6 +75,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
pop_indent()
ret += mcgen('''
+end:
visit_end_struct(m, errp);
}
''')
@@ -122,6 +126,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
return;
}
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
+ if (obj && !*obj) {
+ goto end;
+ }
visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
if (err) {
error_propagate(errp, err);
commit b6f0474fc0fe6f81d93d620a5d24bc30b22d561b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:06 2012 +0100
qapi: shortcut visits on errors
We can exit very soon if we enter a visitor with a preexisting error.
This simplifies some cases because we will not have to deal with
obj being non-NULL while *obj is NULL.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 78c947c..4297621 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -61,6 +61,9 @@ def generate_visit_struct(name, members):
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
{
+ if (error_is_set(errp)) {
+ return;
+ }
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), errp);
''',
name=name)
@@ -81,6 +84,9 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name,
{
GenericList *i, **head = (GenericList **)obj;
+ if (error_is_set(errp)) {
+ return;
+ }
visit_start_list(m, name, errp);
for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) {
@@ -112,6 +118,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
{
Error *err = NULL;
+ if (error_is_set(errp)) {
+ return;
+ }
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
if (err) {
commit 8b714d3747e6870db85dd9382adb8ee371633092
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:05 2012 +0100
qapi: fix memory leak on error
QmpInputVisitor would leak the malloced struct if the stack was
overflowed. This can be easily fixed using error_propagate.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index b4013cc..ef9288f 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -86,6 +86,7 @@ static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
{
QmpInputVisitor *qiv = to_qiv(v);
const QObject *qobj = qmp_input_get_object(qiv, name);
+ Error *err = NULL;
if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -93,8 +94,9 @@ static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
return;
}
- qmp_input_push(qiv, qobj, errp);
- if (error_is_set(errp)) {
+ qmp_input_push(qiv, qobj, &err);
+ if (err) {
+ error_propagate(errp, err);
return;
}
commit 2c7ff93359e820f90bfb4ac9efd6ec35949e5630
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:04 2012 +0100
qapi: fail hard on stack imbalance
QmpOutputVisitor will segfault if an imbalanced end function is
called. So we can abort in QmpInputVisitor too.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index e6b6152..b4013cc 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -77,11 +77,8 @@ static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **err
static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
{
+ assert(qiv->nb_stack > 0);
qiv->nb_stack--;
- if (qiv->nb_stack < 0) {
- error_set(errp, QERR_BUFFER_OVERRUN);
- return;
- }
}
static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
commit 3dcf71f632a0a41ff8c9a27f7cf967c647806c07
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 22 12:51:03 2012 +0100
qapi: add a test case for type errors
There is no test case for parse errors, add one.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
index 1996e49..c30fdc4 100644
--- a/test-qmp-input-visitor.c
+++ b/test-qmp-input-visitor.c
@@ -258,6 +258,23 @@ static void input_visitor_test_add(const char *testpath,
visitor_input_teardown);
}
+static void test_visitor_in_errors(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ g_assert(p->string == NULL);
+
+ g_free(p->string);
+ g_free(p);
+}
+
int main(int argc, char **argv)
{
TestInputVisitorData in_visitor_data;
@@ -282,6 +299,8 @@ int main(int argc, char **argv)
&in_visitor_data, test_visitor_in_list);
input_visitor_test_add("/visitor/input/union",
&in_visitor_data, test_visitor_in_union);
+ input_visitor_test_add("/visitor/input/errors",
+ &in_visitor_data, test_visitor_in_errors);
g_test_run();
commit 9e9eace89e2a8180f0a5fd312bb87e53e6f2004b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Mar 20 11:22:49 2012 +0100
qapi: add struct-errors test case to test-qmp-output-visitor
This test case verifies that invalid native enums are caught, and causes
qapi to tear down the QObject tree under construction, exercising the
previous patch.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qapi-schema-test.json b/qapi-schema-test.json
index 8c7f9f7..9eae350 100644
--- a/qapi-schema-test.json
+++ b/qapi-schema-test.json
@@ -8,7 +8,7 @@
# for testing nested structs
{ 'type': 'UserDefOne',
- 'data': { 'integer': 'int', 'string': 'str' } }
+ 'data': { 'integer': 'int', 'string': 'str', '*enum1': 'EnumOne' } }
{ 'type': 'UserDefTwo',
'data': { 'string': 'str',
diff --git a/test-qmp-output-visitor.c b/test-qmp-output-visitor.c
index 4d6c4d4..24a6359 100644
--- a/test-qmp-output-visitor.c
+++ b/test-qmp-output-visitor.c
@@ -274,6 +274,24 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
qapi_free_UserDefNested(ud2);
}
+static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
+ const void *unused)
+{
+ EnumOne bad_values[] = { ENUM_ONE_MAX, -1 };
+ UserDefOne u = { 0 }, *pu = &u;
+ Error *errp;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
+ errp = NULL;
+ u.has_enum1 = true;
+ u.enum1 = bad_values[i];
+ visit_type_UserDefOne(data->ov, &pu, "unused", &errp);
+ g_assert(error_is_set(&errp) == true);
+ error_free(errp);
+ }
+}
+
typedef struct TestStructList
{
TestStruct *value;
@@ -444,6 +462,8 @@ int main(int argc, char **argv)
&out_visitor_data, test_visitor_out_struct);
output_visitor_test_add("/visitor/output/struct-nested",
&out_visitor_data, test_visitor_out_struct_nested);
+ output_visitor_test_add("/visitor/output/struct-errors",
+ &out_visitor_data, test_visitor_out_struct_errors);
output_visitor_test_add("/visitor/output/list",
&out_visitor_data, test_visitor_out_list);
output_visitor_test_add("/visitor/output/list-qapi-free",
commit f24582d6ad8a080e008974c000bf0ae635d036ac
Author: Laszlo Ersek <lersek at redhat.com>
Date: Tue Mar 20 11:22:48 2012 +0100
qapi: fix double free in qmp_output_visitor_cleanup()
Stack entries in QmpOutputVisitor are navigation links (weak references),
except the bottom (ie. least recently added) entry, which owns the root
QObject [1]. Make qmp_output_visitor_cleanup() drop the stack entries,
then release the QObject tree by the root.
Attempting to serialize an invalid enum inside a dictionary is an example
for triggering the double free.
[1] http://lists.nongnu.org/archive/html/qemu-devel/2012-03/msg03276.html
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index e0697b0..2bce9d5 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -199,14 +199,16 @@ void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
{
QStackEntry *e, *tmp;
+ /* The bottom QStackEntry, if any, owns the root QObject. See the
+ * qmp_output_push_obj() invocations in qmp_output_add_obj(). */
+ QObject *root = QTAILQ_EMPTY(&v->stack) ? NULL : qmp_output_first(v);
+
QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
QTAILQ_REMOVE(&v->stack, e, node);
- if (e->value) {
- qobject_decref(e->value);
- }
g_free(e);
}
+ qobject_decref(root);
g_free(v);
}
commit 8a22565b7c2d1920b02b94e7a8021c65895a3a22
Merge: 29b18b7... e72c3f2...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Mar 26 15:17:51 2012 -0500
Merge remote-tracking branch 'mdroth/qga-pull-3-26-12' into staging
* mdroth/qga-pull-3-26-12:
qemu-ga: fix bsd build, and re-org linux-specific implementations
commit 29b18b7a53c0b5053e895947b0b9008120632f9b
Merge: 3d032f0... 95b752b...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Mar 26 15:08:26 2012 -0500
Merge remote-tracking branch 'stefanha/trivial-patches' into staging
* stefanha/trivial-patches:
trace-events: Fix broken build caused by wrong format specifier
test: add test-qmp-commands to make check
qapi: remove print statements from test-qmp-commands
test: remove qemu-ga reference
vl.c: fix '-cpu ?' segfault
commit 3d032f0f5a7968e1721dd6eca00b61ee84510411
Merge: 81fe74d... a13ccc9...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Mar 26 15:08:15 2012 -0500
Merge remote-tracking branch 'spice/spice.v51' into staging
* spice/spice.v51:
ui/spice-display: use uintptr_t when casting qxl physical addresses
ui/spice-display.c: Fix compilation warnings on 32 bit hosts
commit 81fe74dc1cffc9451bf836e732e526b3ce3e085b
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Wed Mar 21 10:10:46 2012 -0500
test: remove qemu-ga reference
This was added by mistake a while back.
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile b/Makefile
index 8d6b558..d8e1f36 100644
--- a/Makefile
+++ b/Makefile
@@ -173,6 +173,7 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
$(qapi-obj-y): $(GENERATED_HEADERS)
qapi-dir := $(BUILD_DIR)/qapi-generated
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
+qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
gen-out-type = $(subst .,-,$(suffix $@))
diff --git a/tests/Makefile b/tests/Makefile
index c78ade1..354fdbb 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -17,7 +17,7 @@ test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y)
test-qmp-input-visitor.o test-qmp-output-visitor.o \
test-string-input-visitor.o test-string-output-visitor.o \
- test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
+ test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
commit 3017b72cd0f4c7f7df9e93d3f7a4f600669187f7
Author: Miroslav Rezanina <mrezanin at redhat.com>
Date: Wed Mar 21 13:46:54 2012 +0100
Man page: Add -global description
There's only TODO information in qemu man page for -global option. This is a basic description of this option with simple example.
Signed-off-by: Miroslav Rezanina <mrezanin at redhat.com>
v4:
- break long line
v3:
- add use case description
- use prop instead of property
v2:
- Use better value in example
Patch:
--
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qemu-options.hx b/qemu-options.hx
index daefce3..662f571 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -288,13 +288,21 @@ TODO
ETEXI
DEF("global", HAS_ARG, QEMU_OPTION_global,
- "-global driver.property=value\n"
+ "-global driver.prop=value\n"
" set a global default for a driver property\n",
QEMU_ARCH_ALL)
STEXI
- at item -global
+ at item -global @var{driver}. at var{prop}=@var{value}
@findex -global
-TODO
+Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.:
+
+ at example
+qemu -global ide-drive.physical_block_size=4096 -drive file=file,if=ide,index=0,media=disk
+ at end example
+
+In particular, you can use this to set driver properties for devices which are
+created automatically by the machine model. To create a device which is not
+created automatically and set properties on it, use - at option{device}.
ETEXI
DEF("mtdblock", HAS_ARG, QEMU_OPTION_mtdblock,
commit c9da228b49792354af6bb6735bc48bc1c156bc0d
Author: Federico Simoncelli <fsimonce at redhat.com>
Date: Tue Mar 20 13:54:35 2012 +0000
qapi: add c_fun to escape function names
Signed-off-by: Federico Simoncelli <fsimonce at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 3aabf61..30a24d2 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -42,7 +42,7 @@ def generate_command_decl(name, args, ret_type):
return mcgen('''
%(ret_type)s qmp_%(name)s(%(args)sError **errp);
''',
- ret_type=c_type(ret_type), name=c_var(name), args=arglist).strip()
+ ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip()
def gen_sync_call(name, args, ret_type, indent=0):
ret = ""
@@ -59,7 +59,7 @@ def gen_sync_call(name, args, ret_type, indent=0):
%(retval)sqmp_%(name)s(%(args)serrp);
''',
- name=c_var(name), args=arglist, retval=retval).rstrip()
+ name=c_fun(name), args=arglist, retval=retval).rstrip()
if ret_type:
ret += "\n" + mcgen(''''
if (!error_is_set(errp)) {
@@ -74,7 +74,7 @@ if (!error_is_set(errp)) {
def gen_marshal_output_call(name, ret_type):
if not ret_type:
return ""
- return "qmp_marshal_output_%s(retval, ret, errp);" % c_var(name)
+ return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name)
def gen_visitor_output_containers_decl(ret_type):
ret = ""
@@ -198,16 +198,16 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o
qapi_dealloc_visitor_cleanup(md);
}
''',
- c_ret_type=c_type(ret_type), c_name=c_var(name),
+ c_ret_type=c_type(ret_type), c_name=c_fun(name),
visitor=type_visitor(ret_type))
return ret
def gen_marshal_input_decl(name, args, ret_type, middle_mode):
if middle_mode:
- return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_var(name)
+ return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_fun(name)
else:
- return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_var(name)
+ return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_fun(name)
@@ -298,7 +298,7 @@ def gen_registry(commands):
registry += mcgen('''
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
''',
- name=cmd['command'], c_name=c_var(cmd['command']))
+ name=cmd['command'], c_name=c_fun(cmd['command']))
pop_indent()
ret = mcgen('''
static void qmp_init_marshal(void)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 727fb77..4a734f5 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -100,7 +100,7 @@ typedef enum %(name)s
%(abbrev)s_%(value)s = %(i)d,
''',
abbrev=de_camel_case(name).upper(),
- value=c_var(value).upper(),
+ value=c_fun(value).upper(),
i=i)
i += 1
@@ -126,7 +126,7 @@ struct %(name)s
%(c_type)s %(c_name)s;
''',
c_type=c_type(typeinfo[key]),
- c_name=c_var(key))
+ c_name=c_fun(key))
ret += mcgen('''
};
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 54117d4..78c947c 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -129,9 +129,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
break;
''',
abbrev = de_camel_case(name).upper(),
- enum = de_camel_case(key).upper(),
+ enum = c_fun(de_camel_case(key)).upper(),
c_type=members[key],
- c_name=c_var(key))
+ c_name=c_fun(key))
ret += mcgen('''
default:
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6e05469..e062336 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -131,7 +131,10 @@ def camel_case(name):
return new_name
def c_var(name):
- return '_'.join(name.split('-')).lstrip("*")
+ return name.replace('-', '_').lstrip("*")
+
+def c_fun(name):
+ return c_var(name).replace('.', '_')
def c_list_type(name):
return '%sList' % name
commit 6f06f178f96de3597e1098258ab5d11733ae8602
Author: Alon Levy <alevy at redhat.com>
Date: Thu Mar 22 20:00:36 2012 +0200
libcacard/vcard_emul_nss: add warning for old coolkey
Older coolkey versions (before the future fix of RHBZ 802435) have
a fake card reader created if no reader is detected during module
initialization. Warn libcacard users if the faulty coolkey is detected
by checking for the fake reader name "E-Gate 0 0".
Signed-off-by: Alon Levy <alevy at redhat.com>
diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c
index 3703fdc..802cae3 100644
--- a/libcacard/vcard_emul_nss.c
+++ b/libcacard/vcard_emul_nss.c
@@ -1018,6 +1018,16 @@ vcard_emul_init(const VCardEmulOptions *options)
if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) {
continue;
}
+ if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) {
+ /*
+ * coolkey <= 1.1.0-20 emulates this reader if it can't find
+ * any hardware readers. This causes problems, warn user of
+ * problems.
+ */
+ fprintf(stderr, "known bad coolkey version - see "
+ "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n");
+ continue;
+ }
vreader_emul = vreader_emul_new(slot, options->hw_card_type,
options->hw_type_params);
vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
commit 4e339882362102da63ab060f952d249a99ab6752
Author: Alon Levy <alevy at redhat.com>
Date: Thu Mar 22 19:58:58 2012 +0200
libcacard/vcard_emul_nss: handle no readers at startup
When starting with no readers, coolkey should show no slots (with
RHBZ 806038 fixed). Fix initialization to launch the event handling
thread for each module that isn't the internal module regardless of the
number of slots detected for it at initialization time, since slot
number may start as 0 and is dynamic.
RHBZ: 802435
Signed-off-by: Alon Levy <alevy at redhat.com>
diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c
index 7de5d5b..3703fdc 100644
--- a/libcacard/vcard_emul_nss.c
+++ b/libcacard/vcard_emul_nss.c
@@ -1005,10 +1005,10 @@ vcard_emul_init(const VCardEmulOptions *options)
SECMOD_GetReadLock(module_lock);
for (mlp = module_list; mlp; mlp = mlp->next) {
SECMODModule *module = mlp->module;
- PRBool has_emul_slots = PR_FALSE;
- if (module == NULL) {
- continue;
+ /* Ignore the internal module */
+ if (module == NULL || module == SECMOD_GetInternalModule()) {
+ continue;
}
for (i = 0; i < module->slotCount; i++) {
@@ -1024,9 +1024,6 @@ vcard_emul_init(const VCardEmulOptions *options)
vreader_emul_delete);
vreader_add_reader(vreader);
- has_readers = PR_TRUE;
- has_emul_slots = PR_TRUE;
-
if (PK11_IsPresent(slot)) {
VCard *vcard;
vcard = vcard_emul_mirror_card(vreader);
@@ -1035,12 +1032,10 @@ vcard_emul_init(const VCardEmulOptions *options)
vcard_free(vcard);
}
}
- if (has_emul_slots) {
- vcard_emul_new_event_thread(module);
- }
+ vcard_emul_new_event_thread(module);
}
SECMOD_ReleaseReadLock(module_lock);
- nss_emul_init = has_readers;
+ nss_emul_init = PR_TRUE;
return VCARD_EMUL_OK;
}
commit 1b902f7defa9f5229f92dfb32406c5b30c8045ab
Author: Alon Levy <alevy at redhat.com>
Date: Thu Mar 22 19:44:49 2012 +0200
libcacard/vcard_emul_nss: don't stop thread when there are no slots
Signed-off-by: Alon Levy <alevy at redhat.com>
diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c
index bdc3c79..7de5d5b 100644
--- a/libcacard/vcard_emul_nss.c
+++ b/libcacard/vcard_emul_nss.c
@@ -682,8 +682,19 @@ vcard_emul_event_thread(void *arg)
SECMODModule *module = (SECMODModule *)arg;
do {
+ /*
+ * XXX - the latency value doesn't matter one bit. you only get no
+ * blocking (flags |= CKF_DONT_BLOCK) or PKCS11_WAIT_LATENCY (==500),
+ * hard coded in coolkey. And it isn't coolkey's fault - the timeout
+ * value we pass get's dropped on the floor before C_WaitForSlotEvent
+ * is called.
+ */
slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
if (slot == NULL) {
+ /* this could be just a no event indication */
+ if (PORT_GetError() == SEC_ERROR_NO_EVENT) {
+ continue;
+ }
break;
}
vreader = vcard_emul_find_vreader_from_slot(slot);
commit 95b752bc32ccabe48430c0d0062b7c6947d864d0
Author: Stefan Weil <sw at weilnetz.de>
Date: Sat Mar 24 08:13:34 2012 +0100
trace-events: Fix broken build caused by wrong format specifier
mem is an uint64_t value, so %lx was wrong.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/trace-events b/trace-events
index 70f059d..db2cd39 100644
--- a/trace-events
+++ b/trace-events
@@ -726,7 +726,7 @@ ppm_save(const char *filename, void *display_surface) "%s surface=%p"
# hw/qxl.c
disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d"
disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u"
-qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %dx%d mem=%lx %d,%d"
+qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %ux%u mem=%" PRIx64 " %u,%u"
qxl_create_guest_primary_rest(int qid, int32_t stride, uint32_t type, uint32_t flags) "%d %d,%d,%d"
qxl_destroy_primary(int qid) "%d"
qxl_enter_vga_mode(int qid) "%d"
commit 2db5b068ac16dc1d5403503d829ed9b046aca20c
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Mon Mar 19 19:18:26 2012 -0500
test: add test-qmp-commands to make check
All the deps are here but the test was never added to the list of tests
for make check
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/tests/Makefile b/tests/Makefile
index 354fdbb..94ea342 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -3,6 +3,7 @@ export SRC_PATH
CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist
CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor
CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine
+CHECKS += test-qmp-commands
CHECKS += $(SRC_PATH)/tests/qemu-iotests-quick.sh
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
commit 151c5693258f594541fa9ea585547a0a8dd68abc
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Mon Mar 19 19:18:25 2012 -0500
qapi: remove print statements from test-qmp-commands
This is necessary for nicer make check integration.
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/test-qmp-commands.c b/test-qmp-commands.c
index fa5a7bd..60cbf01 100644
--- a/test-qmp-commands.c
+++ b/test-qmp-commands.c
@@ -46,7 +46,6 @@ static void test_dispatch_cmd(void)
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
- g_print("\nresp: %s\n", qstring_get_str(qobject_to_json(resp)));
qobject_decref(resp);
QDECREF(req);
@@ -63,7 +62,6 @@ static void test_dispatch_cmd_error(void)
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(qdict_haskey(qobject_to_qdict(resp), "error"));
- g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
qobject_decref(resp);
QDECREF(req);
@@ -92,7 +90,6 @@ static void test_dispatch_cmd_io(void)
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
- g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
qobject_decref(resp);
QDECREF(req);
commit 3ac805d9223ba9b9e38570ed5883c410746a34da
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Wed Mar 21 10:10:46 2012 -0500
test: remove qemu-ga reference
This was added by mistake a while back.
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/Makefile b/Makefile
index 8d6b558..d8e1f36 100644
--- a/Makefile
+++ b/Makefile
@@ -173,6 +173,7 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
$(qapi-obj-y): $(GENERATED_HEADERS)
qapi-dir := $(BUILD_DIR)/qapi-generated
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
+qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
gen-out-type = $(subst .,-,$(suffix $@))
diff --git a/tests/Makefile b/tests/Makefile
index c78ade1..354fdbb 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -17,7 +17,7 @@ test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y)
test-qmp-input-visitor.o test-qmp-output-visitor.o \
test-string-input-visitor.o test-string-output-visitor.o \
- test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
+ test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
commit 1d6528af68ca4afa3177d18542155976df505872
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Mar 21 09:33:40 2012 -0300
vl.c: fix '-cpu ?' segfault
Fix stupid copy&paste mistake at commit
ecf40beae7dcbb057d4f115207f9d8276832a774: I moved code around but kept
"optarg" on the cpu_list() call.
Reported-by: Jiri Denemark <jdenemar at redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/vl.c b/vl.c
index 112b0e0..0fccf50 100644
--- a/vl.c
+++ b/vl.c
@@ -3196,7 +3196,7 @@ int main(int argc, char **argv, char **envp)
cpudef_init();
if (cpu_model && *cpu_model == '?') {
- list_cpus(stdout, &fprintf, optarg);
+ list_cpus(stdout, &fprintf, cpu_model);
exit(0);
}
commit e72c3f2ed9c4fe482ebe34d1079a9ebb8baca552
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Sun Mar 25 13:59:41 2012 -0500
qemu-ga: fix bsd build, and re-org linux-specific implementations
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 7b2be2f..faf970d 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -12,29 +12,30 @@
*/
#include <glib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "qga/guest-agent-core.h"
+#include "qga-qmp-commands.h"
+#include "qerror.h"
+#include "qemu-queue.h"
+#include "host-utils.h"
#if defined(__linux__)
#include <mntent.h>
#include <linux/fs.h>
-
-#if defined(__linux__) && defined(FIFREEZE)
-#define CONFIG_FSFREEZE
-#endif
-#endif
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/wait.h>
-#include "qga/guest-agent-core.h"
-#include "qga-qmp-commands.h"
-#include "qerror.h"
-#include "qemu-queue.h"
-#include "host-utils.h"
+#if defined(__linux__) && defined(FIFREEZE)
+#define CONFIG_FSFREEZE
+#endif
+#endif
+
+#if defined(__linux__)
+/* TODO: use this in place of all post-fork() fclose(std*) callers */
static void reopen_fd_to_null(int fd)
{
int nullfd;
@@ -50,6 +51,7 @@ static void reopen_fd_to_null(int fd)
close(nullfd);
}
}
+#endif /* defined(__linux__) */
void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
{
@@ -309,7 +311,11 @@ static void guest_file_init(void)
QTAILQ_INIT(&guest_file_state.filehandles);
}
+/* linux-specific implementations. avoid this if at all possible. */
+#if defined(__linux__)
+
#if defined(CONFIG_FSFREEZE)
+
static void disable_logging(void)
{
ga_disable_logging(ga_state);
@@ -505,38 +511,7 @@ static void guest_fsfreeze_cleanup(void)
}
}
}
-#else
-/*
- * Return status of freeze/thaw
- */
-GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
-{
- error_set(err, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-/*
- * Walk list of mounted file systems in the guest, and freeze the ones which
- * are real local file systems.
- */
-int64_t qmp_guest_fsfreeze_freeze(Error **err)
-{
- error_set(err, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-/*
- * Walk list of frozen file systems in the guest, and thaw them.
- */
-int64_t qmp_guest_fsfreeze_thaw(Error **err)
-{
- error_set(err, QERR_UNSUPPORTED);
-
- return 0;
-}
-#endif
+#endif /* CONFIG_FSFREEZE */
#define LINUX_SYS_STATE_FILE "/sys/power/state"
#define SUSPEND_SUPPORTED 0
@@ -904,6 +879,52 @@ error:
return NULL;
}
+#else /* defined(__linux__) */
+
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
+}
+
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
+}
+
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
+}
+
+void qmp_guest_suspend_disk(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+}
+
+void qmp_guest_suspend_ram(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+}
+
+void qmp_guest_suspend_hybrid(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+}
+
+GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
+{
+ error_set(errp, QERR_UNSUPPORTED);
+ return NULL;
+}
+
+#endif
+
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
commit cb1977d308f6e1d6bf398d42e6148187b82456c1
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 10:47:39 2012 -0700
tcg-sparc: Add debug_frame support.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/elf.h b/elf.h
index 310e05a..36bcac4 100644
--- a/elf.h
+++ b/elf.h
@@ -346,6 +346,21 @@ typedef struct {
#define R_MIPS_HIVENDOR 127
+/* SUN SPARC specific definitions. */
+
+/* Values for Elf64_Ehdr.e_flags. */
+
+#define EF_SPARCV9_MM 3
+#define EF_SPARCV9_TSO 0
+#define EF_SPARCV9_PSO 1
+#define EF_SPARCV9_RMO 2
+#define EF_SPARC_LEDATA 0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK 0xFFFF00
+#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
+
/*
* Sparc ELF relocation types
*/
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 491c979..247a278 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -1624,3 +1624,66 @@ static void tcg_target_init(TCGContext *s)
tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7);
tcg_add_target_add_op_defs(sparc_op_defs);
}
+
+#if TCG_TARGET_REG_BITS == 64
+# define ELF_HOST_MACHINE EM_SPARCV9
+#elif defined(__sparc_v8plus__)
+# define ELF_HOST_MACHINE EM_SPARC32PLUS
+# define ELF_HOST_FLAGS EF_SPARC_32PLUS
+#else
+# define ELF_HOST_MACHINE EM_SPARC
+#endif
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t id;
+ uint8_t version;
+ char augmentation[1];
+ uint8_t code_align;
+ uint8_t data_align;
+ uint8_t return_column;
+} DebugFrameCIE;
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t cie_offset;
+ tcg_target_long func_start __attribute__((packed));
+ tcg_target_long func_len __attribute__((packed));
+ uint8_t def_cfa[TCG_TARGET_REG_BITS == 64 ? 4 : 2];
+ uint8_t win_save;
+ uint8_t ret_save[3];
+} DebugFrameFDE;
+
+typedef struct {
+ DebugFrameCIE cie;
+ DebugFrameFDE fde;
+} DebugFrame;
+
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = -sizeof(void *) & 0x7f,
+ .cie.return_column = 15, /* o7 */
+
+ .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+ .fde.def_cfa = {
+#if TCG_TARGET_REG_BITS == 64
+ 12, 30, /* DW_CFA_def_cfa i6, 2047 */
+ (2047 & 0x7f) | 0x80, (2047 >> 7)
+#else
+ 13, 30 /* DW_CFA_def_cfa_register i6 */
+#endif
+ },
+ .fde.win_save = 0x2d, /* DW_CFA_GNU_window_save */
+ .fde.ret_save = { 9, 15, 31 }, /* DW_CFA_register o7, i7 */
+};
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+ debug_frame.fde.func_start = (tcg_target_long) buf;
+ debug_frame.fde.func_len = buf_size;
+
+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
commit e7bd63006412cb21bf2616f464955cf875a0f627
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 10:47:38 2012 -0700
tcg-hppa: Add debug_frame support.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
index e579ef0..2885212 100644
--- a/tcg/hppa/tcg-target.c
+++ b/tcg/hppa/tcg-target.c
@@ -336,7 +336,7 @@ static int tcg_target_const_match(tcg_target_long val,
#define INSN_COMIBF (INSN_OP(0x23))
/* supplied by libgcc */
-extern void *__canonicalize_funcptr_for_compare(void *);
+extern void *__canonicalize_funcptr_for_compare(const void *);
static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
{
@@ -628,7 +628,7 @@ static void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp)
tcg_out_shd(s, ret, arg, temp, 8); /* ret = DCBA */
}
-static void tcg_out_call(TCGContext *s, void *func)
+static void tcg_out_call(TCGContext *s, const void *func)
{
tcg_target_long val, hi, lo, disp;
@@ -1661,23 +1661,18 @@ static int tcg_target_callee_save_regs[] = {
TCG_REG_R18
};
+#define FRAME_SIZE ((-TCG_TARGET_CALL_STACK_OFFSET \
+ + TCG_TARGET_STATIC_CALL_ARGS_SIZE \
+ + ARRAY_SIZE(tcg_target_callee_save_regs) * 4 \
+ + CPU_TEMP_BUF_NLONGS * sizeof(long) \
+ + TCG_TARGET_STACK_ALIGN - 1) \
+ & -TCG_TARGET_STACK_ALIGN)
+
static void tcg_target_qemu_prologue(TCGContext *s)
{
int frame_size, i;
- /* Allocate space for the fixed frame marker. */
- frame_size = -TCG_TARGET_CALL_STACK_OFFSET;
- frame_size += TCG_TARGET_STATIC_CALL_ARGS_SIZE;
-
- /* Allocate space for the saved registers. */
- frame_size += ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
-
- /* Allocate space for the TCG temps. */
- frame_size += CPU_TEMP_BUF_NLONGS * sizeof(long);
-
- /* Align the allocated space. */
- frame_size = ((frame_size + TCG_TARGET_STACK_ALIGN - 1)
- & -TCG_TARGET_STACK_ALIGN);
+ frame_size = FRAME_SIZE;
/* The return address is stored in the caller's frame. */
tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_CALL_STACK, -20);
@@ -1752,3 +1747,81 @@ static void tcg_target_init(TCGContext *s)
tcg_add_target_add_op_defs(hppa_op_defs);
}
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t id;
+ uint8_t version;
+ char augmentation[1];
+ uint8_t code_align;
+ uint8_t data_align;
+ uint8_t return_column;
+} DebugFrameCIE;
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t cie_offset;
+ tcg_target_long func_start __attribute__((packed));
+ tcg_target_long func_len __attribute__((packed));
+ uint8_t def_cfa[4];
+ uint8_t ret_ofs[3];
+ uint8_t reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2];
+} DebugFrameFDE;
+
+typedef struct {
+ DebugFrameCIE cie;
+ DebugFrameFDE fde;
+} DebugFrame;
+
+#define ELF_HOST_MACHINE EM_PARISC
+#define ELF_HOST_FLAGS EFA_PARISC_1_1
+
+/* ??? BFD (and thus GDB) wants very much to distinguish between HPUX
+ and other extensions. We don't really care, but if we don't set this
+ to *something* then the object file won't be properly matched. */
+#define ELF_OSABI ELFOSABI_LINUX
+
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = 1,
+ .cie.return_column = 2,
+
+ .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+ .fde.def_cfa = {
+ 0x12, 30, /* DW_CFA_def_cfa_sf sp, ... */
+ (-FRAME_SIZE & 0x7f) | 0x80, /* ... sleb128 -FRAME_SIZE */
+ (-FRAME_SIZE >> 7) & 0x7f
+ },
+ .fde.ret_ofs = {
+ 0x11, 2, (-20 / 4) & 0x7f /* DW_CFA_offset_extended_sf r2, 20 */
+ },
+ .fde.reg_ofs = {
+ /* This must match the ordering in tcg_target_callee_save_regs. */
+ 0x80 + 4, 0, /* DW_CFA_offset r4, 0 */
+ 0x80 + 5, 4, /* DW_CFA_offset r5, 4 */
+ 0x80 + 6, 8, /* DW_CFA_offset r6, 8 */
+ 0x80 + 7, 12, /* ... */
+ 0x80 + 8, 16,
+ 0x80 + 9, 20,
+ 0x80 + 10, 24,
+ 0x80 + 11, 28,
+ 0x80 + 12, 32,
+ 0x80 + 13, 36,
+ 0x80 + 14, 40,
+ 0x80 + 15, 44,
+ 0x80 + 16, 48,
+ 0x80 + 17, 52,
+ 0x80 + 18, 56,
+ }
+};
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+ debug_frame.fde.func_start = (tcg_target_long) buf;
+ debug_frame.fde.func_len = buf_size;
+
+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
commit abbb3eae1033a5ba6058457336cce9370146d425
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 10:47:37 2012 -0700
tcg: Allow ELF_HOST_FLAGS and ELF_OSABI overrides in gdb-jit.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tcg/tcg.c b/tcg/tcg.c
index df4edc0..ab589c7 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2360,6 +2360,12 @@ static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
.e_shentsize = sizeof(ElfW(Shdr)),
.e_shnum = ARRAY_SIZE(img->shdr),
.e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
+#ifdef ELF_HOST_FLAGS
+ .e_flags = ELF_HOST_FLAGS,
+#endif
+#ifdef ELF_OSABI
+ .e_ident[EI_OSABI] = ELF_OSABI,
+#endif
},
.phdr = {
.p_type = PT_LOAD,
commit 5872bbf24e524899d002dc4fc9a8544b8334137a
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 10:47:36 2012 -0700
tcg: Add debug_info to JIT ELF image.
This allows us to actually supply a function name in softmmu builds;
gdb doesn't pick up the minimal symbol table otherwise. Also add a
bit of documentation and statically generate more of the ELF image.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tcg/tcg.c b/tcg/tcg.c
index eb595ce..df4edc0 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2252,8 +2252,17 @@ void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
#endif
#ifdef ELF_HOST_MACHINE
-/* The backend should define ELF_HOST_MACHINE to indicate both what value to
- put into the ELF image and to indicate support for the feature. */
+/* In order to use this feature, the backend needs to do three things:
+
+ (1) Define ELF_HOST_MACHINE to indicate both what value to
+ put into the ELF image and to indicate support for the feature.
+
+ (2) Define tcg_register_jit. This should create a buffer containing
+ the contents of a .debug_frame section that describes the post-
+ prologue unwind info for the tcg machine.
+
+ (3) Call tcg_register_jit_int, with the constructed .debug_frame.
+*/
/* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */
typedef enum {
@@ -2300,96 +2309,169 @@ static int find_string(const char *strtab, const char *str)
}
}
-static void tcg_register_jit_int(void *buf, size_t buf_size,
+static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
void *debug_frame, size_t debug_frame_size)
{
- static const char strings[64] =
- "\0"
- ".text\0"
- ".debug_frame\0"
- ".symtab\0"
- ".strtab\0"
- "code_gen_buffer";
+ struct __attribute__((packed)) DebugInfo {
+ uint32_t len;
+ uint16_t version;
+ uint32_t abbrev;
+ uint8_t ptr_size;
+ uint8_t cu_die;
+ uint16_t cu_lang;
+ uintptr_t cu_low_pc;
+ uintptr_t cu_high_pc;
+ uint8_t fn_die;
+ char fn_name[16];
+ uintptr_t fn_low_pc;
+ uintptr_t fn_high_pc;
+ uint8_t cu_eoc;
+ };
struct ElfImage {
ElfW(Ehdr) ehdr;
ElfW(Phdr) phdr;
- ElfW(Shdr) shdr[5];
- ElfW(Sym) sym[1];
- char str[64];
+ ElfW(Shdr) shdr[7];
+ ElfW(Sym) sym[2];
+ struct DebugInfo di;
+ uint8_t da[24];
+ char str[80];
+ };
+
+ struct ElfImage *img;
+
+ static const struct ElfImage img_template = {
+ .ehdr = {
+ .e_ident[EI_MAG0] = ELFMAG0,
+ .e_ident[EI_MAG1] = ELFMAG1,
+ .e_ident[EI_MAG2] = ELFMAG2,
+ .e_ident[EI_MAG3] = ELFMAG3,
+ .e_ident[EI_CLASS] = ELF_CLASS,
+ .e_ident[EI_DATA] = ELF_DATA,
+ .e_ident[EI_VERSION] = EV_CURRENT,
+ .e_type = ET_EXEC,
+ .e_machine = ELF_HOST_MACHINE,
+ .e_version = EV_CURRENT,
+ .e_phoff = offsetof(struct ElfImage, phdr),
+ .e_shoff = offsetof(struct ElfImage, shdr),
+ .e_ehsize = sizeof(ElfW(Shdr)),
+ .e_phentsize = sizeof(ElfW(Phdr)),
+ .e_phnum = 1,
+ .e_shentsize = sizeof(ElfW(Shdr)),
+ .e_shnum = ARRAY_SIZE(img->shdr),
+ .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
+ },
+ .phdr = {
+ .p_type = PT_LOAD,
+ .p_flags = PF_X,
+ },
+ .shdr = {
+ [0] = { .sh_type = SHT_NULL },
+ /* Trick: The contents of code_gen_buffer are not present in
+ this fake ELF file; that got allocated elsewhere. Therefore
+ we mark .text as SHT_NOBITS (similar to .bss) so that readers
+ will not look for contents. We can record any address. */
+ [1] = { /* .text */
+ .sh_type = SHT_NOBITS,
+ .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
+ },
+ [2] = { /* .debug_info */
+ .sh_type = SHT_PROGBITS,
+ .sh_offset = offsetof(struct ElfImage, di),
+ .sh_size = sizeof(struct DebugInfo),
+ },
+ [3] = { /* .debug_abbrev */
+ .sh_type = SHT_PROGBITS,
+ .sh_offset = offsetof(struct ElfImage, da),
+ .sh_size = sizeof(img->da),
+ },
+ [4] = { /* .debug_frame */
+ .sh_type = SHT_PROGBITS,
+ .sh_offset = sizeof(struct ElfImage),
+ },
+ [5] = { /* .symtab */
+ .sh_type = SHT_SYMTAB,
+ .sh_offset = offsetof(struct ElfImage, sym),
+ .sh_size = sizeof(img->sym),
+ .sh_info = 1,
+ .sh_link = ARRAY_SIZE(img->shdr) - 1,
+ .sh_entsize = sizeof(ElfW(Sym)),
+ },
+ [6] = { /* .strtab */
+ .sh_type = SHT_STRTAB,
+ .sh_offset = offsetof(struct ElfImage, str),
+ .sh_size = sizeof(img->str),
+ }
+ },
+ .sym = {
+ [1] = { /* code_gen_buffer */
+ .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
+ .st_shndx = 1,
+ }
+ },
+ .di = {
+ .len = sizeof(struct DebugInfo) - 4,
+ .version = 2,
+ .ptr_size = sizeof(void *),
+ .cu_die = 1,
+ .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */
+ .fn_die = 2,
+ .fn_name = "code_gen_buffer"
+ },
+ .da = {
+ 1, /* abbrev number (the cu) */
+ 0x11, 1, /* DW_TAG_compile_unit, has children */
+ 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */
+ 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */
+ 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */
+ 0, 0, /* end of abbrev */
+ 2, /* abbrev number (the fn) */
+ 0x2e, 0, /* DW_TAG_subprogram, no children */
+ 0x3, 0x8, /* DW_AT_name, DW_FORM_string */
+ 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */
+ 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */
+ 0, 0, /* end of abbrev */
+ 0 /* no more abbrev */
+ },
+ .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
+ ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
};
/* We only need a single jit entry; statically allocate it. */
static struct jit_code_entry one_entry;
+ uintptr_t buf = (uintptr_t)buf_ptr;
size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
- struct ElfImage *img = g_malloc0(img_size);
-
- img->ehdr.e_ident[EI_MAG0] = ELFMAG0;
- img->ehdr.e_ident[EI_MAG1] = ELFMAG1;
- img->ehdr.e_ident[EI_MAG2] = ELFMAG2;
- img->ehdr.e_ident[EI_MAG3] = ELFMAG3;
- img->ehdr.e_ident[EI_CLASS] = ELF_CLASS;
- img->ehdr.e_ident[EI_DATA] = ELF_DATA;
- img->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
- img->ehdr.e_type = ET_EXEC;
- img->ehdr.e_machine = ELF_HOST_MACHINE;
- img->ehdr.e_version = EV_CURRENT;
- img->ehdr.e_phoff = offsetof(struct ElfImage, phdr);
- img->ehdr.e_shoff = offsetof(struct ElfImage, shdr);
- img->ehdr.e_ehsize = sizeof(ElfW(Shdr));
- img->ehdr.e_phentsize = sizeof(ElfW(Phdr));
- img->ehdr.e_phnum = 1;
- img->ehdr.e_shentsize = sizeof(img->shdr[0]);
- img->ehdr.e_shnum = ARRAY_SIZE(img->shdr);
- img->ehdr.e_shstrndx = ARRAY_SIZE(img->shdr) - 1;
-
- img->phdr.p_type = PT_LOAD;
- img->phdr.p_offset = (char *)buf - (char *)img;
- img->phdr.p_vaddr = (ElfW(Addr))buf;
- img->phdr.p_paddr = img->phdr.p_vaddr;
- img->phdr.p_filesz = 0;
- img->phdr.p_memsz = buf_size;
- img->phdr.p_flags = PF_X;
- memcpy(img->str, strings, sizeof(img->str));
+ img = g_malloc(img_size);
+ *img = img_template;
+ memcpy(img + 1, debug_frame, debug_frame_size);
- img->shdr[0].sh_type = SHT_NULL;
+ img->phdr.p_vaddr = buf;
+ img->phdr.p_paddr = buf;
+ img->phdr.p_memsz = buf_size;
- /* Trick: The contents of code_gen_buffer are not present in this fake
- ELF file; that got allocated elsewhere, discontiguously. Therefore
- we mark .text as SHT_NOBITS (similar to .bss) so that readers will
- not look for contents. We can record any address at will. */
img->shdr[1].sh_name = find_string(img->str, ".text");
- img->shdr[1].sh_type = SHT_NOBITS;
- img->shdr[1].sh_flags = SHF_EXECINSTR | SHF_ALLOC;
- img->shdr[1].sh_addr = (ElfW(Addr))buf;
+ img->shdr[1].sh_addr = buf;
img->shdr[1].sh_size = buf_size;
- img->shdr[2].sh_name = find_string(img->str, ".debug_frame");
- img->shdr[2].sh_type = SHT_PROGBITS;
- img->shdr[2].sh_offset = sizeof(*img);
- img->shdr[2].sh_size = debug_frame_size;
- memcpy(img + 1, debug_frame, debug_frame_size);
+ img->shdr[2].sh_name = find_string(img->str, ".debug_info");
+ img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
+
+ img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
+ img->shdr[4].sh_size = debug_frame_size;
+
+ img->shdr[5].sh_name = find_string(img->str, ".symtab");
+ img->shdr[6].sh_name = find_string(img->str, ".strtab");
+
+ img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
+ img->sym[1].st_value = buf;
+ img->sym[1].st_size = buf_size;
- img->shdr[3].sh_name = find_string(img->str, ".symtab");
- img->shdr[3].sh_type = SHT_SYMTAB;
- img->shdr[3].sh_offset = offsetof(struct ElfImage, sym);
- img->shdr[3].sh_size = sizeof(img->sym);
- img->shdr[3].sh_info = ARRAY_SIZE(img->sym);
- img->shdr[3].sh_link = img->ehdr.e_shstrndx;
- img->shdr[3].sh_entsize = sizeof(ElfW(Sym));
-
- img->shdr[4].sh_name = find_string(img->str, ".strtab");
- img->shdr[4].sh_type = SHT_STRTAB;
- img->shdr[4].sh_offset = offsetof(struct ElfImage, str);
- img->shdr[4].sh_size = sizeof(img->str);
-
- img->sym[0].st_name = find_string(img->str, "code_gen_buffer");
- img->sym[0].st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
- img->sym[0].st_shndx = 1;
- img->sym[0].st_value = (ElfW(Addr))buf;
- img->sym[0].st_size = buf_size;
+ img->di.cu_low_pc = buf;
+ img->di.cu_high_pc = buf_size;
+ img->di.fn_low_pc = buf;
+ img->di.fn_high_pc = buf_size;
#ifdef DEBUG_JIT
/* Enable this block to be able to debug the ELF image file creation.
@@ -2397,7 +2479,7 @@ static void tcg_register_jit_int(void *buf, size_t buf_size,
{
FILE *f = fopen("/tmp/qemu.jit", "w+b");
if (f) {
- if (fwrite(img, img_size, 1, f) != buf_size) {
+ if (fwrite(img, img_size, 1, f) != img_size) {
/* Avoid stupid unused return value warning for fwrite. */
}
fclose(f);
@@ -2414,7 +2496,8 @@ static void tcg_register_jit_int(void *buf, size_t buf_size,
__jit_debug_register_code();
}
#else
-/* No support for the feature. Provide the entry point expected by exec.c. */
+/* No support for the feature. Provide the entry point expected by exec.c,
+ and implement the internal function we declared earlier. */
static void tcg_register_jit_int(void *buf, size_t size,
void *debug_frame, size_t debug_frame_size)
commit 55fddd661187bd321343776e2d460cc4e67d225b
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:15 2012 -0700
target-alpha: Use noreturn marker in helper.h.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 9f97c5d..a184def 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -1,6 +1,6 @@
#include "def-helper.h"
-DEF_HELPER_3(excp, void, env, int, int)
+DEF_HELPER_3(excp, noreturn, env, int, int)
DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64, env)
DEF_HELPER_3(addqv, i64, env, i64, i64)
commit 743434099d427c17f6c8f36de81a83f83ec13fb2
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:14 2012 -0700
target-alpha: Make use of fp_status.flush_inputs_to_zero.
This softfp feature post-dates the last major update to the Alpha
fpu translation. We can make use of this to eliminate at least
one helper function that was performing this operation by hand.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c7787f6..6c5d28b 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -234,7 +234,6 @@ struct CPUAlphaState {
uint8_t fpcr_exc_mask;
uint8_t fpcr_dyn_round;
uint8_t fpcr_flush_to_zero;
- uint8_t fpcr_dnz;
uint8_t fpcr_dnod;
uint8_t fpcr_undz;
diff --git a/target-alpha/fpu_helper.c b/target-alpha/fpu_helper.c
index d38521b..dda1103 100644
--- a/target-alpha/fpu_helper.c
+++ b/target-alpha/fpu_helper.c
@@ -88,21 +88,17 @@ void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t exc, uint32_t regno)
}
}
-/* Input remapping without software completion. Handle denormal-map-to-zero
- and trap for all other non-finite numbers. */
-uint64_t helper_ieee_input(CPUAlphaState *env, uint64_t val)
+/* Input handing without software completion. Trap for all
+ non-finite numbers. */
+void helper_ieee_input(CPUAlphaState *env, uint64_t val)
{
uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
uint64_t frac = val & 0xfffffffffffffull;
if (exp == 0) {
- if (frac != 0) {
- /* If DNZ is set flush denormals to zero on input. */
- if (env->fpcr_dnz) {
- val &= 1ull << 63;
- } else {
- arith_excp(env, GETPC(), EXC_M_UNF, 0);
- }
+ /* Denormals without DNZ set raise an exception. */
+ if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
+ arith_excp(env, GETPC(), EXC_M_UNF, 0);
}
} else if (exp == 0x7ff) {
/* Infinity or NaN. */
@@ -111,43 +107,23 @@ uint64_t helper_ieee_input(CPUAlphaState *env, uint64_t val)
just emulates the insn to figure out what exception to use. */
arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
}
- return val;
}
/* Similar, but does not trap for infinities. Used for comparisons. */
-uint64_t helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
+void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
{
uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
uint64_t frac = val & 0xfffffffffffffull;
if (exp == 0) {
- if (frac != 0) {
- /* If DNZ is set flush denormals to zero on input. */
- if (env->fpcr_dnz) {
- val &= 1ull << 63;
- } else {
- arith_excp(env, GETPC(), EXC_M_UNF, 0);
- }
+ /* Denormals without DNZ set raise an exception. */
+ if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
+ arith_excp(env, GETPC(), EXC_M_UNF, 0);
}
} else if (exp == 0x7ff && frac) {
/* NaN. */
arith_excp(env, GETPC(), EXC_M_INV, 0);
}
- return val;
-}
-
-/* Input remapping with software completion enabled. All we have to do
- is handle denormal-map-to-zero; all other inputs get exceptions as
- needed from the actual operation. */
-uint64_t helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
-{
- if (env->fpcr_dnz) {
- uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
- if (exp == 0) {
- val &= 1ull << 63;
- }
- }
- return val;
}
/* F floating (VAX) */
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 3333bfa..765e650 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -82,7 +82,7 @@ uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
break;
}
- if (env->fpcr_dnz) {
+ if (env->fp_status.flush_inputs_to_zero) {
r |= FPCR_DNZ;
}
if (env->fpcr_dnod) {
@@ -151,12 +151,10 @@ void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
}
env->fpcr_dyn_round = t;
- env->fpcr_flush_to_zero
- = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
-
- env->fpcr_dnz = (val & FPCR_DNZ) != 0;
env->fpcr_dnod = (val & FPCR_DNOD) != 0;
env->fpcr_undz = (val & FPCR_UNDZ) != 0;
+ env->fpcr_flush_to_zero = env->fpcr_dnod & env->fpcr_undz;
+ env->fp_status.flush_inputs_to_zero = (val & FPCR_DNZ) != 0;
}
uint64_t helper_load_fpcr(CPUAlphaState *env)
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 03cc185..9f97c5d 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -95,9 +95,8 @@ DEF_HELPER_FLAGS_1(fp_exc_get, TCG_CALL_CONST | TCG_CALL_PURE, i32, env)
DEF_HELPER_3(fp_exc_raise, void, env, i32, i32)
DEF_HELPER_3(fp_exc_raise_s, void, env, i32, i32)
-DEF_HELPER_2(ieee_input, i64, env, i64)
-DEF_HELPER_2(ieee_input_cmp, i64, env, i64)
-DEF_HELPER_2(ieee_input_s, i64, env, i64)
+DEF_HELPER_2(ieee_input, void, env, i64)
+DEF_HELPER_2(ieee_input_cmp, void, env, i64)
#if !defined (CONFIG_USER_ONLY)
DEF_HELPER_2(hw_ret, void, env, i64)
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index dd09ad8..1f4565d 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -661,15 +661,19 @@ static void gen_qual_flushzero(DisasContext *ctx, int fn11)
static TCGv gen_ieee_input(int reg, int fn11, int is_cmp)
{
- TCGv val = tcg_temp_new();
+ TCGv val;
if (reg == 31) {
- tcg_gen_movi_i64(val, 0);
- } else if (fn11 & QUAL_S) {
- gen_helper_ieee_input_s(val, cpu_env, cpu_fir[reg]);
- } else if (is_cmp) {
- gen_helper_ieee_input_cmp(val, cpu_env, cpu_fir[reg]);
+ val = tcg_const_i64(0);
} else {
- gen_helper_ieee_input(val, cpu_env, cpu_fir[reg]);
+ if ((fn11 & QUAL_S) == 0) {
+ if (is_cmp) {
+ gen_helper_ieee_input_cmp(cpu_env, cpu_fir[reg]);
+ } else {
+ gen_helper_ieee_input(cpu_env, cpu_fir[reg]);
+ }
+ }
+ val = tcg_temp_new();
+ tcg_gen_mov_i64(val, cpu_fir[reg]);
}
return val;
}
commit c30827555d5305d42f7b164dc69a381c4882e77a
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:13 2012 -0700
target-alpha: Move memory helpers to mem_helper.c.
This completes the transition away from AREG0. This patch must
be last because it requires CONFIG_TCG_PASS_AREG0 set too.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile.target b/Makefile.target
index 254a9fa..44b2e83 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -81,8 +81,10 @@ libobj-y += tcg/tcg.o tcg/optimize.o
libobj-$(CONFIG_TCG_INTERPRETER) += tci.o
libobj-y += fpu/softfloat.o
ifneq ($(TARGET_BASE_ARCH), sparc)
+ifneq ($(TARGET_BASE_ARCH), alpha)
libobj-y += op_helper.o
endif
+endif
libobj-y += helper.o
ifeq ($(TARGET_BASE_ARCH), i386)
libobj-y += cpuid.o
@@ -96,7 +98,7 @@ libobj-y += cpu_init.o
endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
-libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o
+libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
libobj-y += disas.o
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
diff --git a/configure b/configure
index 8b4e3c1..14ef738 100755
--- a/configure
+++ b/configure
@@ -3608,7 +3608,7 @@ case "$target_arch2" in
esac
case "$target_arch2" in
- sparc*)
+ alpha | sparc*)
echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak
;;
esac
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index f057ecf..03cc185 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -104,12 +104,12 @@ DEF_HELPER_2(hw_ret, void, env, i64)
DEF_HELPER_1(ldl_phys, i64, i64)
DEF_HELPER_1(ldq_phys, i64, i64)
-DEF_HELPER_1(ldl_l_phys, i64, i64)
-DEF_HELPER_1(ldq_l_phys, i64, i64)
+DEF_HELPER_2(ldl_l_phys, i64, env, i64)
+DEF_HELPER_2(ldq_l_phys, i64, env, i64)
DEF_HELPER_2(stl_phys, void, i64, i64)
DEF_HELPER_2(stq_phys, void, i64, i64)
-DEF_HELPER_2(stl_c_phys, i64, i64, i64)
-DEF_HELPER_2(stq_c_phys, i64, i64, i64)
+DEF_HELPER_3(stl_c_phys, i64, env, i64, i64)
+DEF_HELPER_3(stq_c_phys, i64, env, i64, i64)
DEF_HELPER_FLAGS_1(tbia, TCG_CALL_CONST, void, env)
DEF_HELPER_FLAGS_2(tbis, TCG_CALL_CONST, void, env, i64)
diff --git a/target-alpha/mem_helper.c b/target-alpha/mem_helper.c
new file mode 100644
index 0000000..dd5ca49
--- /dev/null
+++ b/target-alpha/mem_helper.c
@@ -0,0 +1,151 @@
+/*
+ * Helpers for loads and stores
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+
+/* Softmmu support */
+#ifndef CONFIG_USER_ONLY
+
+uint64_t helper_ldl_phys(uint64_t p)
+{
+ return (int32_t)ldl_phys(p);
+}
+
+uint64_t helper_ldq_phys(uint64_t p)
+{
+ return ldq_phys(p);
+}
+
+uint64_t helper_ldl_l_phys(CPUAlphaState *env, uint64_t p)
+{
+ env->lock_addr = p;
+ return env->lock_value = (int32_t)ldl_phys(p);
+}
+
+uint64_t helper_ldq_l_phys(CPUAlphaState *env, uint64_t p)
+{
+ env->lock_addr = p;
+ return env->lock_value = ldq_phys(p);
+}
+
+void helper_stl_phys(uint64_t p, uint64_t v)
+{
+ stl_phys(p, v);
+}
+
+void helper_stq_phys(uint64_t p, uint64_t v)
+{
+ stq_phys(p, v);
+}
+
+uint64_t helper_stl_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
+{
+ uint64_t ret = 0;
+
+ if (p == env->lock_addr) {
+ int32_t old = ldl_phys(p);
+ if (old == (int32_t)env->lock_value) {
+ stl_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
+
+ return ret;
+}
+
+uint64_t helper_stq_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
+{
+ uint64_t ret = 0;
+
+ if (p == env->lock_addr) {
+ uint64_t old = ldq_phys(p);
+ if (old == env->lock_value) {
+ stq_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
+
+ return ret;
+}
+
+static void do_unaligned_access(CPUAlphaState *env, target_ulong addr,
+ int is_write, int is_user, void *retaddr)
+{
+ uint64_t pc;
+ uint32_t insn;
+
+ do_restore_state(env, retaddr);
+
+ pc = env->pc;
+ insn = cpu_ldl_code(env, pc);
+
+ env->trap_arg0 = addr;
+ env->trap_arg1 = insn >> 26; /* opcode */
+ env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
+ env->exception_index = EXCP_UNALIGN;
+ env->error_code = 0;
+ cpu_loop_exit(env);
+}
+
+void cpu_unassigned_access(CPUAlphaState *env, target_phys_addr_t addr,
+ int is_write, int is_exec, int unused, int size)
+{
+ env->trap_arg0 = addr;
+ env->trap_arg1 = is_write;
+ dynamic_excp(env, NULL, EXCP_MCHK, 0);
+}
+
+#include "softmmu_exec.h"
+
+#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+ NULL, it means that the function was called in C code (i.e. not
+ from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(CPUAlphaState *env, target_ulong addr, int is_write,
+ int mmu_idx, void *retaddr)
+{
+ int ret;
+
+ ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ if (unlikely(ret != 0)) {
+ do_restore_state(env, retaddr);
+ /* Exception index and error code are already set */
+ cpu_loop_exit(env);
+ }
+}
+#endif /* CONFIG_USER_ONLY */
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
deleted file mode 100644
index df1f01c..0000000
--- a/target-alpha/op_helper.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Alpha emulation cpu micro-operations helpers for qemu.
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "cpu.h"
-#include "dyngen-exec.h"
-#include "host-utils.h"
-#include "softfloat.h"
-#include "helper.h"
-#include "sysemu.h"
-#include "qemu-timer.h"
-
-
-/*****************************************************************************/
-/* Softmmu support */
-#if !defined (CONFIG_USER_ONLY)
-uint64_t helper_ldl_phys(uint64_t p)
-{
- return (int32_t)ldl_phys(p);
-}
-
-uint64_t helper_ldq_phys(uint64_t p)
-{
- return ldq_phys(p);
-}
-
-uint64_t helper_ldl_l_phys(uint64_t p)
-{
- env->lock_addr = p;
- return env->lock_value = (int32_t)ldl_phys(p);
-}
-
-uint64_t helper_ldq_l_phys(uint64_t p)
-{
- env->lock_addr = p;
- return env->lock_value = ldl_phys(p);
-}
-
-void helper_stl_phys(uint64_t p, uint64_t v)
-{
- stl_phys(p, v);
-}
-
-void helper_stq_phys(uint64_t p, uint64_t v)
-{
- stq_phys(p, v);
-}
-
-uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
-{
- uint64_t ret = 0;
-
- if (p == env->lock_addr) {
- int32_t old = ldl_phys(p);
- if (old == (int32_t)env->lock_value) {
- stl_phys(p, v);
- ret = 1;
- }
- }
- env->lock_addr = -1;
-
- return ret;
-}
-
-uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
-{
- uint64_t ret = 0;
-
- if (p == env->lock_addr) {
- uint64_t old = ldq_phys(p);
- if (old == env->lock_value) {
- stq_phys(p, v);
- ret = 1;
- }
- }
- env->lock_addr = -1;
-
- return ret;
-}
-
-static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
- int is_user, void *retaddr)
-{
- uint64_t pc;
- uint32_t insn;
-
- do_restore_state(env, retaddr);
-
- pc = env->pc;
- insn = ldl_code(pc);
-
- env->trap_arg0 = addr;
- env->trap_arg1 = insn >> 26; /* opcode */
- env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
- env->exception_index = EXCP_UNALIGN;
- env->error_code = 0;
- cpu_loop_exit(env);
-}
-
-void QEMU_NORETURN cpu_unassigned_access(CPUAlphaState *env1,
- target_phys_addr_t addr, int is_write,
- int is_exec, int unused, int size)
-{
- env = env1;
- env->trap_arg0 = addr;
- env->trap_arg1 = is_write;
- dynamic_excp(env1, GETPC(), EXCP_MCHK, 0);
-}
-
-#include "softmmu_exec.h"
-
-#define MMUSUFFIX _mmu
-#define ALIGNED_ONLY
-
-#define SHIFT 0
-#include "softmmu_template.h"
-
-#define SHIFT 1
-#include "softmmu_template.h"
-
-#define SHIFT 2
-#include "softmmu_template.h"
-
-#define SHIFT 3
-#include "softmmu_template.h"
-
-/* try to fill the TLB and return an exception if error. If retaddr is
- NULL, it means that the function was called in C code (i.e. not
- from generated code or from helper.c) */
-/* XXX: fix it to restore all registers */
-void tlb_fill(CPUAlphaState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
-{
- CPUAlphaState *saved_env;
- int ret;
-
- saved_env = env;
- env = env1;
- ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
- if (unlikely(ret != 0)) {
- do_restore_state(env, retaddr);
- /* Exception index and error code are already set */
- cpu_loop_exit(env);
- }
- env = saved_env;
-}
-#endif
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index cc87320..dd09ad8 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2867,11 +2867,11 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x2:
/* Longword physical access with lock (hw_ldl_l/p) */
- gen_helper_ldl_l_phys(cpu_ir[ra], addr);
+ gen_helper_ldl_l_phys(cpu_ir[ra], cpu_env, addr);
break;
case 0x3:
/* Quadword physical access with lock (hw_ldq_l/p) */
- gen_helper_ldq_l_phys(cpu_ir[ra], addr);
+ gen_helper_ldq_l_phys(cpu_ir[ra], cpu_env, addr);
break;
case 0x4:
/* Longword virtual PTE fetch (hw_ldl/v) */
@@ -3180,11 +3180,11 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x2:
/* Longword physical access with lock */
- gen_helper_stl_c_phys(val, addr, val);
+ gen_helper_stl_c_phys(val, cpu_env, addr, val);
break;
case 0x3:
/* Quadword physical access with lock */
- gen_helper_stq_c_phys(val, addr, val);
+ gen_helper_stq_c_phys(val, cpu_env, addr, val);
break;
case 0x4:
/* Longword virtual access */
@@ -3420,7 +3420,7 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env,
}
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
- insn = ldl_code(ctx.pc);
+ insn = cpu_ldl_code(env, ctx.pc);
num_insns++;
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
commit 69163fbb0c4d7d3c270bd79d14d6ac076143975e
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:12 2012 -0700
target-alpha: Move palcode support helpers to sys_helper.c.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile.target b/Makefile.target
index 256e7b5..254a9fa 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -96,7 +96,7 @@ libobj-y += cpu_init.o
endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
-libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o
+libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o
libobj-y += disas.o
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 45e187d..f057ecf 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -1,7 +1,7 @@
#include "def-helper.h"
DEF_HELPER_3(excp, void, env, int, int)
-DEF_HELPER_FLAGS_0(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64)
+DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64, env)
DEF_HELPER_3(addqv, i64, env, i64, i64)
DEF_HELPER_3(addlv, i64, env, i64, i64)
@@ -100,7 +100,7 @@ DEF_HELPER_2(ieee_input_cmp, i64, env, i64)
DEF_HELPER_2(ieee_input_s, i64, env, i64)
#if !defined (CONFIG_USER_ONLY)
-DEF_HELPER_1(hw_ret, void, i64)
+DEF_HELPER_2(hw_ret, void, env, i64)
DEF_HELPER_1(ldl_phys, i64, i64)
DEF_HELPER_1(ldq_phys, i64, i64)
@@ -111,13 +111,13 @@ DEF_HELPER_2(stq_phys, void, i64, i64)
DEF_HELPER_2(stl_c_phys, i64, i64, i64)
DEF_HELPER_2(stq_c_phys, i64, i64, i64)
-DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
-DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(tbia, TCG_CALL_CONST, void, env)
+DEF_HELPER_FLAGS_2(tbis, TCG_CALL_CONST, void, env, i64)
DEF_HELPER_1(halt, void, i64);
DEF_HELPER_FLAGS_0(get_time, TCG_CALL_CONST, i64)
-DEF_HELPER_FLAGS_1(set_alarm, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_2(set_alarm, TCG_CALL_CONST, void, env, i64)
#endif
#include "def-helper.h"
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index c51b535..df1f01c 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -25,71 +25,6 @@
#include "sysemu.h"
#include "qemu-timer.h"
-/*****************************************************************************/
-/* Exceptions processing helpers */
-
-uint64_t helper_load_pcc (void)
-{
-#ifndef CONFIG_USER_ONLY
- /* In system mode we have access to a decent high-resolution clock.
- In order to make OS-level time accounting work with the RPCC,
- present it with a well-timed clock fixed at 250MHz. */
- return (((uint64_t)env->pcc_ofs << 32)
- | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
-#else
- /* In user-mode, vm_clock doesn't exist. Just pass through the host cpu
- clock ticks. Also, don't bother taking PCC_OFS into account. */
- return (uint32_t)cpu_get_real_ticks();
-#endif
-}
-
-/* PALcode support special instructions */
-#if !defined (CONFIG_USER_ONLY)
-void helper_hw_ret (uint64_t a)
-{
- env->pc = a & ~3;
- env->intr_flag = 0;
- env->lock_addr = -1;
- if ((a & 1) == 0) {
- env->pal_mode = 0;
- swap_shadow_regs(env);
- }
-}
-
-void helper_tbia(void)
-{
- tlb_flush(env, 1);
-}
-
-void helper_tbis(uint64_t p)
-{
- tlb_flush_page(env, p);
-}
-
-void helper_halt(uint64_t restart)
-{
- if (restart) {
- qemu_system_reset_request();
- } else {
- qemu_system_shutdown_request();
- }
-}
-
-uint64_t helper_get_time(void)
-{
- return qemu_get_clock_ns(rtc_clock);
-}
-
-void helper_set_alarm(uint64_t expire)
-{
- if (expire) {
- env->alarm_expire = expire;
- qemu_mod_timer(env->alarm_timer, expire);
- } else {
- qemu_del_timer(env->alarm_timer);
- }
-}
-#endif
/*****************************************************************************/
/* Softmmu support */
diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c
new file mode 100644
index 0000000..40ca49c
--- /dev/null
+++ b/target-alpha/sys_helper.c
@@ -0,0 +1,87 @@
+/*
+ * Helpers for system instructions.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+
+uint64_t helper_load_pcc(CPUAlphaState *env)
+{
+#ifndef CONFIG_USER_ONLY
+ /* In system mode we have access to a decent high-resolution clock.
+ In order to make OS-level time accounting work with the RPCC,
+ present it with a well-timed clock fixed at 250MHz. */
+ return (((uint64_t)env->pcc_ofs << 32)
+ | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
+#else
+ /* In user-mode, vm_clock doesn't exist. Just pass through the host cpu
+ clock ticks. Also, don't bother taking PCC_OFS into account. */
+ return (uint32_t)cpu_get_real_ticks();
+#endif
+}
+
+/* PALcode support special instructions */
+#ifndef CONFIG_USER_ONLY
+void helper_hw_ret(CPUAlphaState *env, uint64_t a)
+{
+ env->pc = a & ~3;
+ env->intr_flag = 0;
+ env->lock_addr = -1;
+ if ((a & 1) == 0) {
+ env->pal_mode = 0;
+ swap_shadow_regs(env);
+ }
+}
+
+void helper_tbia(CPUAlphaState *env)
+{
+ tlb_flush(env, 1);
+}
+
+void helper_tbis(CPUAlphaState *env, uint64_t p)
+{
+ tlb_flush_page(env, p);
+}
+
+void helper_halt(uint64_t restart)
+{
+ if (restart) {
+ qemu_system_reset_request();
+ } else {
+ qemu_system_shutdown_request();
+ }
+}
+
+uint64_t helper_get_time(void)
+{
+ return qemu_get_clock_ns(rtc_clock);
+}
+
+void helper_set_alarm(CPUAlphaState *env, uint64_t expire)
+{
+ if (expire) {
+ env->alarm_expire = expire;
+ qemu_mod_timer(env->alarm_timer, expire);
+ } else {
+ qemu_del_timer(env->alarm_timer);
+ }
+}
+#endif /* CONFIG_USER_ONLY */
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 551237c..cc87320 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1678,12 +1678,12 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
switch (regno) {
case 255:
/* TBIA */
- gen_helper_tbia();
+ gen_helper_tbia(cpu_env);
break;
case 254:
/* TBIS */
- gen_helper_tbis(tmp);
+ gen_helper_tbis(cpu_env, tmp);
break;
case 253:
@@ -1699,7 +1699,7 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
case 251:
/* ALARM */
- gen_helper_set_alarm(tmp);
+ gen_helper_set_alarm(cpu_env, tmp);
break;
default:
@@ -2793,11 +2793,11 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
if (ra != 31) {
if (use_icount) {
gen_io_start();
- gen_helper_load_pcc(cpu_ir[ra]);
+ gen_helper_load_pcc(cpu_ir[ra], cpu_env);
gen_io_end();
ret = EXIT_PC_STALE;
} else {
- gen_helper_load_pcc(cpu_ir[ra]);
+ gen_helper_load_pcc(cpu_ir[ra], cpu_env);
}
}
break;
@@ -3143,10 +3143,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
emulation PALcode, so continue to accept it. */
TCGv tmp = tcg_temp_new();
tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUAlphaState, exc_addr));
- gen_helper_hw_ret(tmp);
+ gen_helper_hw_ret(cpu_env, tmp);
tcg_temp_free(tmp);
} else {
- gen_helper_hw_ret(cpu_ir[rb]);
+ gen_helper_hw_ret(cpu_env, cpu_ir[rb]);
}
ret = EXIT_PC_UPDATED;
break;
commit 2958620f67dcfd11476e62b4ca704dae0b978ea3
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:11 2012 -0700
target-alpha: Move integer overflow helpers to int_helper.c.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index e193c26..45e187d 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -3,12 +3,12 @@
DEF_HELPER_3(excp, void, env, int, int)
DEF_HELPER_FLAGS_0(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64)
-DEF_HELPER_2(addqv, i64, i64, i64)
-DEF_HELPER_2(addlv, i64, i64, i64)
-DEF_HELPER_2(subqv, i64, i64, i64)
-DEF_HELPER_2(sublv, i64, i64, i64)
-DEF_HELPER_2(mullv, i64, i64, i64)
-DEF_HELPER_2(mulqv, i64, i64, i64)
+DEF_HELPER_3(addqv, i64, env, i64, i64)
+DEF_HELPER_3(addlv, i64, env, i64, i64)
+DEF_HELPER_3(subqv, i64, env, i64, i64)
+DEF_HELPER_3(sublv, i64, env, i64, i64)
+DEF_HELPER_3(mullv, i64, env, i64, i64)
+DEF_HELPER_3(mulqv, i64, env, i64, i64)
DEF_HELPER_FLAGS_2(umulh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
diff --git a/target-alpha/int_helper.c b/target-alpha/int_helper.c
index 79c0cfe..1d832f0 100644
--- a/target-alpha/int_helper.c
+++ b/target-alpha/int_helper.c
@@ -255,3 +255,65 @@ uint64_t helper_unpkbw(uint64_t op1)
| ((op1 & 0xff0000) << 16)
| ((op1 & 0xff000000) << 24));
}
+
+uint64_t helper_addqv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint64_t tmp = op1;
+ op1 += op2;
+ if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return op1;
+}
+
+uint64_t helper_addlv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint64_t tmp = op1;
+ op1 = (uint32_t)(op1 + op2);
+ if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return op1;
+}
+
+uint64_t helper_subqv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint64_t res;
+ res = op1 - op2;
+ if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return res;
+}
+
+uint64_t helper_sublv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint32_t res;
+ res = op1 - op2;
+ if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return res;
+}
+
+uint64_t helper_mullv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ int64_t res = (int64_t)op1 * (int64_t)op2;
+
+ if (unlikely((int32_t)res != res)) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return (int64_t)((int32_t)res);
+}
+
+uint64_t helper_mulqv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint64_t tl, th;
+
+ muls64(&tl, &th, op1, op2);
+ /* If th != 0 && th != -1, then we had an overflow */
+ if (unlikely((th + 1) > 1)) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return tl;
+}
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 59ee31e..c51b535 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -43,68 +43,6 @@ uint64_t helper_load_pcc (void)
#endif
}
-uint64_t helper_addqv (uint64_t op1, uint64_t op2)
-{
- uint64_t tmp = op1;
- op1 += op2;
- if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
- arith_excp(env, GETPC(), EXC_M_IOV, 0);
- }
- return op1;
-}
-
-uint64_t helper_addlv (uint64_t op1, uint64_t op2)
-{
- uint64_t tmp = op1;
- op1 = (uint32_t)(op1 + op2);
- if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
- arith_excp(env, GETPC(), EXC_M_IOV, 0);
- }
- return op1;
-}
-
-uint64_t helper_subqv (uint64_t op1, uint64_t op2)
-{
- uint64_t res;
- res = op1 - op2;
- if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
- arith_excp(env, GETPC(), EXC_M_IOV, 0);
- }
- return res;
-}
-
-uint64_t helper_sublv (uint64_t op1, uint64_t op2)
-{
- uint32_t res;
- res = op1 - op2;
- if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
- arith_excp(env, GETPC(), EXC_M_IOV, 0);
- }
- return res;
-}
-
-uint64_t helper_mullv (uint64_t op1, uint64_t op2)
-{
- int64_t res = (int64_t)op1 * (int64_t)op2;
-
- if (unlikely((int32_t)res != res)) {
- arith_excp(env, GETPC(), EXC_M_IOV, 0);
- }
- return (int64_t)((int32_t)res);
-}
-
-uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
-{
- uint64_t tl, th;
-
- muls64(&tl, &th, op1, op2);
- /* If th != 0 && th != -1, then we had an overflow */
- if (unlikely((th + 1) > 1)) {
- arith_excp(env, GETPC(), EXC_M_IOV, 0);
- }
- return tl;
-}
-
/* PALcode support special instructions */
#if !defined (CONFIG_USER_ONLY)
void helper_hw_ret (uint64_t a)
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 6f31b6d..551237c 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1392,14 +1392,8 @@ static inline void glue(gen_, name)(int ra, int rb, int rc, int islit,\
tcg_temp_free(tmp1); \
} \
}
-ARITH3(cmpbge)
-ARITH3(addlv)
-ARITH3(sublv)
-ARITH3(addqv)
-ARITH3(subqv)
ARITH3(umulh)
-ARITH3(mullv)
-ARITH3(mulqv)
+ARITH3(cmpbge)
ARITH3(minub8)
ARITH3(minsb8)
ARITH3(minuw4)
@@ -1410,6 +1404,43 @@ ARITH3(maxuw4)
ARITH3(maxsw4)
ARITH3(perr)
+/* Code to call arith3 helpers */
+#define ARITH3_EX(name) \
+ static inline void glue(gen_, name)(int ra, int rb, int rc, \
+ int islit, uint8_t lit) \
+ { \
+ if (unlikely(rc == 31)) { \
+ return; \
+ } \
+ if (ra != 31) { \
+ if (islit) { \
+ TCGv tmp = tcg_const_i64(lit); \
+ gen_helper_ ## name(cpu_ir[rc], cpu_env, \
+ cpu_ir[ra], tmp); \
+ tcg_temp_free(tmp); \
+ } else { \
+ gen_helper_ ## name(cpu_ir[rc], cpu_env, \
+ cpu_ir[ra], cpu_ir[rb]); \
+ } \
+ } else { \
+ TCGv tmp1 = tcg_const_i64(0); \
+ if (islit) { \
+ TCGv tmp2 = tcg_const_i64(lit); \
+ gen_helper_ ## name(cpu_ir[rc], cpu_env, tmp1, tmp2); \
+ tcg_temp_free(tmp2); \
+ } else { \
+ gen_helper_ ## name(cpu_ir[rc], cpu_env, tmp1, cpu_ir[rb]); \
+ } \
+ tcg_temp_free(tmp1); \
+ } \
+ }
+ARITH3_EX(addlv)
+ARITH3_EX(sublv)
+ARITH3_EX(addqv)
+ARITH3_EX(subqv)
+ARITH3_EX(mullv)
+ARITH3_EX(mulqv)
+
#define MVIOP2(name) \
static inline void glue(gen_, name)(int rb, int rc) \
{ \
commit a44a27775af6e745be50b23ae0f0aeb6f8462c80
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:10 2012 -0700
target-alpha: Move fpcr helpers from op_helper.c to helper.c.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 584457f..3333bfa 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -159,9 +159,19 @@ void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
env->fpcr_undz = (val & FPCR_UNDZ) != 0;
}
+uint64_t helper_load_fpcr(CPUAlphaState *env)
+{
+ return cpu_alpha_load_fpcr(env);
+}
+
+void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
+{
+ cpu_alpha_store_fpcr(env, val);
+}
+
#if defined(CONFIG_USER_ONLY)
-int cpu_alpha_handle_mmu_fault (CPUAlphaState *env, target_ulong address, int rw,
- int mmu_idx)
+int cpu_alpha_handle_mmu_fault(CPUAlphaState *env, target_ulong address,
+ int rw, int mmu_idx)
{
env->exception_index = EXCP_MMFAULT;
env->trap_arg0 = address;
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index d36df5f..e193c26 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -34,8 +34,8 @@ DEF_HELPER_FLAGS_1(pkwb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
DEF_HELPER_FLAGS_1(unpkbl, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
DEF_HELPER_FLAGS_1(unpkbw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
-DEF_HELPER_FLAGS_0(load_fpcr, TCG_CALL_CONST | TCG_CALL_PURE, i64)
-DEF_HELPER_FLAGS_1(store_fpcr, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(load_fpcr, TCG_CALL_CONST | TCG_CALL_PURE, i64, env)
+DEF_HELPER_FLAGS_2(store_fpcr, TCG_CALL_CONST, void, env, i64)
DEF_HELPER_FLAGS_1(f_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64)
DEF_HELPER_FLAGS_1(memory_to_f, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 6711d99..59ee31e 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -43,16 +43,6 @@ uint64_t helper_load_pcc (void)
#endif
}
-uint64_t helper_load_fpcr (void)
-{
- return cpu_alpha_load_fpcr (env);
-}
-
-void helper_store_fpcr (uint64_t val)
-{
- cpu_alpha_store_fpcr (env, val);
-}
-
uint64_t helper_addqv (uint64_t op1, uint64_t op2)
{
uint64_t tmp = op1;
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index a9b97a3..6f31b6d 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2678,17 +2678,17 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
case 0x024:
/* MT_FPCR */
if (likely(ra != 31))
- gen_helper_store_fpcr(cpu_fir[ra]);
+ gen_helper_store_fpcr(cpu_env, cpu_fir[ra]);
else {
TCGv tmp = tcg_const_i64(0);
- gen_helper_store_fpcr(tmp);
+ gen_helper_store_fpcr(cpu_env, tmp);
tcg_temp_free(tmp);
}
break;
case 0x025:
/* MF_FPCR */
if (likely(ra != 31))
- gen_helper_load_fpcr(cpu_fir[ra]);
+ gen_helper_load_fpcr(cpu_fir[ra], cpu_env);
break;
case 0x02A:
/* FCMOVEQ */
commit 4a58aedff479e02c33ba74d752f34944751ba28b
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:09 2012 -0700
target-alpha: Move floating-point helpers to fpu_helper.c.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile.target b/Makefile.target
index ddeb7e0..256e7b5 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -96,7 +96,7 @@ libobj-y += cpu_init.o
endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
-libobj-$(TARGET_ALPHA) += int_helper.o
+libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o
libobj-y += disas.o
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
diff --git a/target-alpha/fpu_helper.c b/target-alpha/fpu_helper.c
new file mode 100644
index 0000000..d38521b
--- /dev/null
+++ b/target-alpha/fpu_helper.c
@@ -0,0 +1,846 @@
+/*
+ * Helpers for floating point instructions.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "softfloat.h"
+
+#define FP_STATUS (env->fp_status)
+
+
+void helper_setroundmode(CPUAlphaState *env, uint32_t val)
+{
+ set_float_rounding_mode(val, &FP_STATUS);
+}
+
+void helper_setflushzero(CPUAlphaState *env, uint32_t val)
+{
+ set_flush_to_zero(val, &FP_STATUS);
+}
+
+void helper_fp_exc_clear(CPUAlphaState *env)
+{
+ set_float_exception_flags(0, &FP_STATUS);
+}
+
+uint32_t helper_fp_exc_get(CPUAlphaState *env)
+{
+ return get_float_exception_flags(&FP_STATUS);
+}
+
+static inline void inline_fp_exc_raise(CPUAlphaState *env, void *retaddr,
+ uint32_t exc, uint32_t regno)
+{
+ if (exc) {
+ uint32_t hw_exc = 0;
+
+ if (exc & float_flag_invalid) {
+ hw_exc |= EXC_M_INV;
+ }
+ if (exc & float_flag_divbyzero) {
+ hw_exc |= EXC_M_DZE;
+ }
+ if (exc & float_flag_overflow) {
+ hw_exc |= EXC_M_FOV;
+ }
+ if (exc & float_flag_underflow) {
+ hw_exc |= EXC_M_UNF;
+ }
+ if (exc & float_flag_inexact) {
+ hw_exc |= EXC_M_INE;
+ }
+
+ arith_excp(env, retaddr, hw_exc, 1ull << regno);
+ }
+}
+
+/* Raise exceptions for ieee fp insns without software completion.
+ In that case there are no exceptions that don't trap; the mask
+ doesn't apply. */
+void helper_fp_exc_raise(CPUAlphaState *env, uint32_t exc, uint32_t regno)
+{
+ inline_fp_exc_raise(env, GETPC(), exc, regno);
+}
+
+/* Raise exceptions for ieee fp insns with software completion. */
+void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t exc, uint32_t regno)
+{
+ if (exc) {
+ env->fpcr_exc_status |= exc;
+ exc &= ~env->fpcr_exc_mask;
+ inline_fp_exc_raise(env, GETPC(), exc, regno);
+ }
+}
+
+/* Input remapping without software completion. Handle denormal-map-to-zero
+ and trap for all other non-finite numbers. */
+uint64_t helper_ieee_input(CPUAlphaState *env, uint64_t val)
+{
+ uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
+ uint64_t frac = val & 0xfffffffffffffull;
+
+ if (exp == 0) {
+ if (frac != 0) {
+ /* If DNZ is set flush denormals to zero on input. */
+ if (env->fpcr_dnz) {
+ val &= 1ull << 63;
+ } else {
+ arith_excp(env, GETPC(), EXC_M_UNF, 0);
+ }
+ }
+ } else if (exp == 0x7ff) {
+ /* Infinity or NaN. */
+ /* ??? I'm not sure these exception bit flags are correct. I do
+ know that the Linux kernel, at least, doesn't rely on them and
+ just emulates the insn to figure out what exception to use. */
+ arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
+ }
+ return val;
+}
+
+/* Similar, but does not trap for infinities. Used for comparisons. */
+uint64_t helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
+{
+ uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
+ uint64_t frac = val & 0xfffffffffffffull;
+
+ if (exp == 0) {
+ if (frac != 0) {
+ /* If DNZ is set flush denormals to zero on input. */
+ if (env->fpcr_dnz) {
+ val &= 1ull << 63;
+ } else {
+ arith_excp(env, GETPC(), EXC_M_UNF, 0);
+ }
+ }
+ } else if (exp == 0x7ff && frac) {
+ /* NaN. */
+ arith_excp(env, GETPC(), EXC_M_INV, 0);
+ }
+ return val;
+}
+
+/* Input remapping with software completion enabled. All we have to do
+ is handle denormal-map-to-zero; all other inputs get exceptions as
+ needed from the actual operation. */
+uint64_t helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
+{
+ if (env->fpcr_dnz) {
+ uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
+ if (exp == 0) {
+ val &= 1ull << 63;
+ }
+ }
+ return val;
+}
+
+/* F floating (VAX) */
+static uint64_t float32_to_f(float32 fa)
+{
+ uint64_t r, exp, mant, sig;
+ CPU_FloatU a;
+
+ a.f = fa;
+ sig = ((uint64_t)a.l & 0x80000000) << 32;
+ exp = (a.l >> 23) & 0xff;
+ mant = ((uint64_t)a.l & 0x007fffff) << 29;
+
+ if (exp == 255) {
+ /* NaN or infinity */
+ r = 1; /* VAX dirty zero */
+ } else if (exp == 0) {
+ if (mant == 0) {
+ /* Zero */
+ r = 0;
+ } else {
+ /* Denormalized */
+ r = sig | ((exp + 1) << 52) | mant;
+ }
+ } else {
+ if (exp >= 253) {
+ /* Overflow */
+ r = 1; /* VAX dirty zero */
+ } else {
+ r = sig | ((exp + 2) << 52);
+ }
+ }
+
+ return r;
+}
+
+static float32 f_to_float32(CPUAlphaState *env, void *retaddr, uint64_t a)
+{
+ uint32_t exp, mant_sig;
+ CPU_FloatU r;
+
+ exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
+ mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);
+
+ if (unlikely(!exp && mant_sig)) {
+ /* Reserved operands / Dirty zero */
+ dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
+ }
+
+ if (exp < 3) {
+ /* Underflow */
+ r.l = 0;
+ } else {
+ r.l = ((exp - 2) << 23) | mant_sig;
+ }
+
+ return r.f;
+}
+
+uint32_t helper_f_to_memory(uint64_t a)
+{
+ uint32_t r;
+ r = (a & 0x00001fffe0000000ull) >> 13;
+ r |= (a & 0x07ffe00000000000ull) >> 45;
+ r |= (a & 0xc000000000000000ull) >> 48;
+ return r;
+}
+
+uint64_t helper_memory_to_f(uint32_t a)
+{
+ uint64_t r;
+ r = ((uint64_t)(a & 0x0000c000)) << 48;
+ r |= ((uint64_t)(a & 0x003fffff)) << 45;
+ r |= ((uint64_t)(a & 0xffff0000)) << 13;
+ if (!(a & 0x00004000)) {
+ r |= 0x7ll << 59;
+ }
+ return r;
+}
+
+/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should
+ either implement VAX arithmetic properly or just signal invalid opcode. */
+
+uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = f_to_float32(env, GETPC(), a);
+ fb = f_to_float32(env, GETPC(), b);
+ fr = float32_add(fa, fb, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = f_to_float32(env, GETPC(), a);
+ fb = f_to_float32(env, GETPC(), b);
+ fr = float32_sub(fa, fb, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = f_to_float32(env, GETPC(), a);
+ fb = f_to_float32(env, GETPC(), b);
+ fr = float32_mul(fa, fb, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = f_to_float32(env, GETPC(), a);
+ fb = f_to_float32(env, GETPC(), b);
+ fr = float32_div(fa, fb, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t)
+{
+ float32 ft, fr;
+
+ ft = f_to_float32(env, GETPC(), t);
+ fr = float32_sqrt(ft, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+
+/* G floating (VAX) */
+static uint64_t float64_to_g(float64 fa)
+{
+ uint64_t r, exp, mant, sig;
+ CPU_DoubleU a;
+
+ a.d = fa;
+ sig = a.ll & 0x8000000000000000ull;
+ exp = (a.ll >> 52) & 0x7ff;
+ mant = a.ll & 0x000fffffffffffffull;
+
+ if (exp == 2047) {
+ /* NaN or infinity */
+ r = 1; /* VAX dirty zero */
+ } else if (exp == 0) {
+ if (mant == 0) {
+ /* Zero */
+ r = 0;
+ } else {
+ /* Denormalized */
+ r = sig | ((exp + 1) << 52) | mant;
+ }
+ } else {
+ if (exp >= 2045) {
+ /* Overflow */
+ r = 1; /* VAX dirty zero */
+ } else {
+ r = sig | ((exp + 2) << 52);
+ }
+ }
+
+ return r;
+}
+
+static float64 g_to_float64(CPUAlphaState *env, void *retaddr, uint64_t a)
+{
+ uint64_t exp, mant_sig;
+ CPU_DoubleU r;
+
+ exp = (a >> 52) & 0x7ff;
+ mant_sig = a & 0x800fffffffffffffull;
+
+ if (!exp && mant_sig) {
+ /* Reserved operands / Dirty zero */
+ dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
+ }
+
+ if (exp < 3) {
+ /* Underflow */
+ r.ll = 0;
+ } else {
+ r.ll = ((exp - 2) << 52) | mant_sig;
+ }
+
+ return r.d;
+}
+
+uint64_t helper_g_to_memory(uint64_t a)
+{
+ uint64_t r;
+ r = (a & 0x000000000000ffffull) << 48;
+ r |= (a & 0x00000000ffff0000ull) << 16;
+ r |= (a & 0x0000ffff00000000ull) >> 16;
+ r |= (a & 0xffff000000000000ull) >> 48;
+ return r;
+}
+
+uint64_t helper_memory_to_g(uint64_t a)
+{
+ uint64_t r;
+ r = (a & 0x000000000000ffffull) << 48;
+ r |= (a & 0x00000000ffff0000ull) << 16;
+ r |= (a & 0x0000ffff00000000ull) >> 16;
+ r |= (a & 0xffff000000000000ull) >> 48;
+ return r;
+}
+
+uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+ fr = float64_add(fa, fb, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+ fr = float64_sub(fa, fb, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+ fr = float64_mul(fa, fb, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+ fr = float64_div(fa, fb, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fr = float64_sqrt(fa, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+
+/* S floating (single) */
+
+/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
+static inline uint64_t float32_to_s_int(uint32_t fi)
+{
+ uint32_t frac = fi & 0x7fffff;
+ uint32_t sign = fi >> 31;
+ uint32_t exp_msb = (fi >> 30) & 1;
+ uint32_t exp_low = (fi >> 23) & 0x7f;
+ uint32_t exp;
+
+ exp = (exp_msb << 10) | exp_low;
+ if (exp_msb) {
+ if (exp_low == 0x7f) {
+ exp = 0x7ff;
+ }
+ } else {
+ if (exp_low != 0x00) {
+ exp |= 0x380;
+ }
+ }
+
+ return (((uint64_t)sign << 63)
+ | ((uint64_t)exp << 52)
+ | ((uint64_t)frac << 29));
+}
+
+static inline uint64_t float32_to_s(float32 fa)
+{
+ CPU_FloatU a;
+ a.f = fa;
+ return float32_to_s_int(a.l);
+}
+
+static inline uint32_t s_to_float32_int(uint64_t a)
+{
+ return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
+}
+
+static inline float32 s_to_float32(uint64_t a)
+{
+ CPU_FloatU r;
+ r.l = s_to_float32_int(a);
+ return r.f;
+}
+
+uint32_t helper_s_to_memory(uint64_t a)
+{
+ return s_to_float32_int(a);
+}
+
+uint64_t helper_memory_to_s(uint32_t a)
+{
+ return float32_to_s_int(a);
+}
+
+uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = s_to_float32(a);
+ fb = s_to_float32(b);
+ fr = float32_add(fa, fb, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = s_to_float32(a);
+ fb = s_to_float32(b);
+ fr = float32_sub(fa, fb, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = s_to_float32(a);
+ fb = s_to_float32(b);
+ fr = float32_mul(fa, fb, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = s_to_float32(a);
+ fb = s_to_float32(b);
+ fr = float32_div(fa, fb, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
+{
+ float32 fa, fr;
+
+ fa = s_to_float32(a);
+ fr = float32_sqrt(fa, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+
+/* T floating (double) */
+static inline float64 t_to_float64(uint64_t a)
+{
+ /* Memory format is the same as float64 */
+ CPU_DoubleU r;
+ r.ll = a;
+ return r.d;
+}
+
+static inline uint64_t float64_to_t(float64 fa)
+{
+ /* Memory format is the same as float64 */
+ CPU_DoubleU r;
+ r.d = fa;
+ return r.ll;
+}
+
+uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+ fr = float64_add(fa, fb, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+ fr = float64_sub(fa, fb, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+ fr = float64_mul(fa, fb, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+ fr = float64_div(fa, fb, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa, fr;
+
+ fa = t_to_float64(a);
+ fr = float64_sqrt(fa, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+/* Comparisons */
+uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+
+ if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+
+ if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+
+ if (float64_le(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+
+ if (float64_lt(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+
+ if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+
+ if (float64_le(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+
+ if (float64_lt(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+/* Floating point format conversion */
+uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa;
+ float32 fr;
+
+ fa = t_to_float64(a);
+ fr = float64_to_float32(fa, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
+{
+ float32 fa;
+ float64 fr;
+
+ fa = s_to_float32(a);
+ fr = float32_to_float64(fa, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
+{
+ float32 fr = int64_to_float32(a, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+/* Implement float64 to uint64 conversion without saturation -- we must
+ supply the truncated result. This behaviour is used by the compiler
+ to get unsigned conversion for free with the same instruction.
+
+ The VI flag is set when overflow or inexact exceptions should be raised. */
+
+static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
+ int roundmode, int VI)
+{
+ uint64_t frac, ret = 0;
+ uint32_t exp, sign, exc = 0;
+ int shift;
+
+ sign = (a >> 63);
+ exp = (uint32_t)(a >> 52) & 0x7ff;
+ frac = a & 0xfffffffffffffull;
+
+ if (exp == 0) {
+ if (unlikely(frac != 0)) {
+ goto do_underflow;
+ }
+ } else if (exp == 0x7ff) {
+ exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0);
+ } else {
+ /* Restore implicit bit. */
+ frac |= 0x10000000000000ull;
+
+ shift = exp - 1023 - 52;
+ if (shift >= 0) {
+ /* In this case the number is so large that we must shift
+ the fraction left. There is no rounding to do. */
+ if (shift < 63) {
+ ret = frac << shift;
+ if (VI && (ret >> shift) != frac) {
+ exc = float_flag_overflow;
+ }
+ }
+ } else {
+ uint64_t round;
+
+ /* In this case the number is smaller than the fraction as
+ represented by the 52 bit number. Here we must think
+ about rounding the result. Handle this by shifting the
+ fractional part of the number into the high bits of ROUND.
+ This will let us efficiently handle round-to-nearest. */
+ shift = -shift;
+ if (shift < 63) {
+ ret = frac >> shift;
+ round = frac << (64 - shift);
+ } else {
+ /* The exponent is so small we shift out everything.
+ Leave a sticky bit for proper rounding below. */
+ do_underflow:
+ round = 1;
+ }
+
+ if (round) {
+ exc = (VI ? float_flag_inexact : 0);
+ switch (roundmode) {
+ case float_round_nearest_even:
+ if (round == (1ull << 63)) {
+ /* Fraction is exactly 0.5; round to even. */
+ ret += (ret & 1);
+ } else if (round > (1ull << 63)) {
+ ret += 1;
+ }
+ break;
+ case float_round_to_zero:
+ break;
+ case float_round_up:
+ ret += 1 - sign;
+ break;
+ case float_round_down:
+ ret += sign;
+ break;
+ }
+ }
+ }
+ if (sign) {
+ ret = -ret;
+ }
+ }
+ if (unlikely(exc)) {
+ float_raise(exc, &FP_STATUS);
+ }
+
+ return ret;
+}
+
+uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
+{
+ return inline_cvttq(env, a, FP_STATUS.float_rounding_mode, 1);
+}
+
+uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
+{
+ return inline_cvttq(env, a, float_round_to_zero, 0);
+}
+
+uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a)
+{
+ return inline_cvttq(env, a, float_round_to_zero, 1);
+}
+
+uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
+{
+ float64 fr = int64_to_float64(a, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a)
+{
+ float32 fr = int64_to_float32(a, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa;
+ float32 fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fr = float64_to_float32(fa, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa = g_to_float64(env, GETPC(), a);
+ return float64_to_int64_round_to_zero(fa, &FP_STATUS);
+}
+
+uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a)
+{
+ float64 fr;
+ fr = int64_to_float64(a, &FP_STATUS);
+ return float64_to_g(fr);
+}
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 91a9e39..d36df5f 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -39,65 +39,65 @@ DEF_HELPER_FLAGS_1(store_fpcr, TCG_CALL_CONST, void, i64)
DEF_HELPER_FLAGS_1(f_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64)
DEF_HELPER_FLAGS_1(memory_to_f, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32)
-DEF_HELPER_FLAGS_2(addf, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(subf, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(mulf, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(divf, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_1(sqrtf, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_3(addf, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(subf, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(mulf, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(divf, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(sqrtf, TCG_CALL_CONST, i64, env, i64)
DEF_HELPER_FLAGS_1(g_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
DEF_HELPER_FLAGS_1(memory_to_g, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
-DEF_HELPER_FLAGS_2(addg, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(subg, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(mulg, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(divg, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_1(sqrtg, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_3(addg, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(subg, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(mulg, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(divg, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(sqrtg, TCG_CALL_CONST, i64, env, i64)
DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64)
DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32)
-DEF_HELPER_FLAGS_2(adds, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(subs, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(muls, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(divs, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_1(sqrts, TCG_CALL_CONST, i64, i64)
-
-DEF_HELPER_FLAGS_2(addt, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(subt, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(mult, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(divt, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_1(sqrtt, TCG_CALL_CONST, i64, i64)
-
-DEF_HELPER_FLAGS_2(cmptun, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmpteq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmptle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmptlt, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmpgeq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmpgle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmpglt, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_1(cvtts, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtst, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtqs, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtqt, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtqf, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtgf, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtgq, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtqg, TCG_CALL_CONST, i64, i64)
-
-DEF_HELPER_FLAGS_1(cvttq, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvttq_c, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvttq_svic, TCG_CALL_CONST, i64, i64)
-
-DEF_HELPER_FLAGS_1(setroundmode, TCG_CALL_CONST, void, i32)
-DEF_HELPER_FLAGS_1(setflushzero, TCG_CALL_CONST, void, i32)
-DEF_HELPER_FLAGS_0(fp_exc_clear, TCG_CALL_CONST, void)
-DEF_HELPER_FLAGS_0(fp_exc_get, TCG_CALL_CONST | TCG_CALL_PURE, i32)
-DEF_HELPER_2(fp_exc_raise, void, i32, i32)
-DEF_HELPER_2(fp_exc_raise_s, void, i32, i32)
-
-DEF_HELPER_1(ieee_input, i64, i64)
-DEF_HELPER_1(ieee_input_cmp, i64, i64)
-DEF_HELPER_1(ieee_input_s, i64, i64)
+DEF_HELPER_FLAGS_3(adds, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(subs, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(muls, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(divs, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(sqrts, TCG_CALL_CONST, i64, env, i64)
+
+DEF_HELPER_FLAGS_3(addt, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(subt, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(mult, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(divt, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(sqrtt, TCG_CALL_CONST, i64, env, i64)
+
+DEF_HELPER_FLAGS_3(cmptun, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmpteq, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmptle, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmptlt, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmpgeq, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmpgle, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmpglt, TCG_CALL_CONST, i64, env, i64, i64)
+
+DEF_HELPER_FLAGS_2(cvtts, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtst, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtqs, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtqt, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtqf, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtgf, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtgq, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtqg, TCG_CALL_CONST, i64, env, i64)
+
+DEF_HELPER_FLAGS_2(cvttq, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvttq_c, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvttq_svic, TCG_CALL_CONST, i64, env, i64)
+
+DEF_HELPER_FLAGS_2(setroundmode, TCG_CALL_CONST, void, env, i32)
+DEF_HELPER_FLAGS_2(setflushzero, TCG_CALL_CONST, void, env, i32)
+DEF_HELPER_FLAGS_1(fp_exc_clear, TCG_CALL_CONST, void, env)
+DEF_HELPER_FLAGS_1(fp_exc_get, TCG_CALL_CONST | TCG_CALL_PURE, i32, env)
+DEF_HELPER_3(fp_exc_raise, void, env, i32, i32)
+DEF_HELPER_3(fp_exc_raise_s, void, env, i32, i32)
+
+DEF_HELPER_2(ieee_input, i64, env, i64)
+DEF_HELPER_2(ieee_input_cmp, i64, env, i64)
+DEF_HELPER_2(ieee_input_s, i64, env, i64)
#if !defined (CONFIG_USER_ONLY)
DEF_HELPER_1(hw_ret, void, i64)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index af5fa82..6711d99 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -25,8 +25,6 @@
#include "sysemu.h"
#include "qemu-timer.h"
-#define FP_STATUS (env->fp_status)
-
/*****************************************************************************/
/* Exceptions processing helpers */
@@ -117,816 +115,6 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
return tl;
}
-/* Floating point helpers */
-
-void helper_setroundmode (uint32_t val)
-{
- set_float_rounding_mode(val, &FP_STATUS);
-}
-
-void helper_setflushzero (uint32_t val)
-{
- set_flush_to_zero(val, &FP_STATUS);
-}
-
-void helper_fp_exc_clear (void)
-{
- set_float_exception_flags(0, &FP_STATUS);
-}
-
-uint32_t helper_fp_exc_get (void)
-{
- return get_float_exception_flags(&FP_STATUS);
-}
-
-/* Raise exceptions for ieee fp insns without software completion.
- In that case there are no exceptions that don't trap; the mask
- doesn't apply. */
-void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
-{
- if (exc) {
- uint32_t hw_exc = 0;
-
- if (exc & float_flag_invalid) {
- hw_exc |= EXC_M_INV;
- }
- if (exc & float_flag_divbyzero) {
- hw_exc |= EXC_M_DZE;
- }
- if (exc & float_flag_overflow) {
- hw_exc |= EXC_M_FOV;
- }
- if (exc & float_flag_underflow) {
- hw_exc |= EXC_M_UNF;
- }
- if (exc & float_flag_inexact) {
- hw_exc |= EXC_M_INE;
- }
-
- arith_excp(env, GETPC(), hw_exc, 1ull << regno);
- }
-}
-
-/* Raise exceptions for ieee fp insns with software completion. */
-void helper_fp_exc_raise_s(uint32_t exc, uint32_t regno)
-{
- if (exc) {
- env->fpcr_exc_status |= exc;
-
- exc &= ~env->fpcr_exc_mask;
- if (exc) {
- helper_fp_exc_raise(exc, regno);
- }
- }
-}
-
-/* Input remapping without software completion. Handle denormal-map-to-zero
- and trap for all other non-finite numbers. */
-uint64_t helper_ieee_input(uint64_t val)
-{
- uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
- uint64_t frac = val & 0xfffffffffffffull;
-
- if (exp == 0) {
- if (frac != 0) {
- /* If DNZ is set flush denormals to zero on input. */
- if (env->fpcr_dnz) {
- val &= 1ull << 63;
- } else {
- arith_excp(env, GETPC(), EXC_M_UNF, 0);
- }
- }
- } else if (exp == 0x7ff) {
- /* Infinity or NaN. */
- /* ??? I'm not sure these exception bit flags are correct. I do
- know that the Linux kernel, at least, doesn't rely on them and
- just emulates the insn to figure out what exception to use. */
- arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
- }
- return val;
-}
-
-/* Similar, but does not trap for infinities. Used for comparisons. */
-uint64_t helper_ieee_input_cmp(uint64_t val)
-{
- uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
- uint64_t frac = val & 0xfffffffffffffull;
-
- if (exp == 0) {
- if (frac != 0) {
- /* If DNZ is set flush denormals to zero on input. */
- if (env->fpcr_dnz) {
- val &= 1ull << 63;
- } else {
- arith_excp(env, GETPC(), EXC_M_UNF, 0);
- }
- }
- } else if (exp == 0x7ff && frac) {
- /* NaN. */
- arith_excp(env, GETPC(), EXC_M_INV, 0);
- }
- return val;
-}
-
-/* Input remapping with software completion enabled. All we have to do
- is handle denormal-map-to-zero; all other inputs get exceptions as
- needed from the actual operation. */
-uint64_t helper_ieee_input_s(uint64_t val)
-{
- if (env->fpcr_dnz) {
- uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
- if (exp == 0) {
- val &= 1ull << 63;
- }
- }
- return val;
-}
-
-/* F floating (VAX) */
-static inline uint64_t float32_to_f(float32 fa)
-{
- uint64_t r, exp, mant, sig;
- CPU_FloatU a;
-
- a.f = fa;
- sig = ((uint64_t)a.l & 0x80000000) << 32;
- exp = (a.l >> 23) & 0xff;
- mant = ((uint64_t)a.l & 0x007fffff) << 29;
-
- if (exp == 255) {
- /* NaN or infinity */
- r = 1; /* VAX dirty zero */
- } else if (exp == 0) {
- if (mant == 0) {
- /* Zero */
- r = 0;
- } else {
- /* Denormalized */
- r = sig | ((exp + 1) << 52) | mant;
- }
- } else {
- if (exp >= 253) {
- /* Overflow */
- r = 1; /* VAX dirty zero */
- } else {
- r = sig | ((exp + 2) << 52);
- }
- }
-
- return r;
-}
-
-static inline float32 f_to_float32(uint64_t a)
-{
- uint32_t exp, mant_sig;
- CPU_FloatU r;
-
- exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
- mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);
-
- if (unlikely(!exp && mant_sig)) {
- /* Reserved operands / Dirty zero */
- dynamic_excp(env, GETPC(), EXCP_OPCDEC, 0);
- }
-
- if (exp < 3) {
- /* Underflow */
- r.l = 0;
- } else {
- r.l = ((exp - 2) << 23) | mant_sig;
- }
-
- return r.f;
-}
-
-uint32_t helper_f_to_memory (uint64_t a)
-{
- uint32_t r;
- r = (a & 0x00001fffe0000000ull) >> 13;
- r |= (a & 0x07ffe00000000000ull) >> 45;
- r |= (a & 0xc000000000000000ull) >> 48;
- return r;
-}
-
-uint64_t helper_memory_to_f (uint32_t a)
-{
- uint64_t r;
- r = ((uint64_t)(a & 0x0000c000)) << 48;
- r |= ((uint64_t)(a & 0x003fffff)) << 45;
- r |= ((uint64_t)(a & 0xffff0000)) << 13;
- if (!(a & 0x00004000))
- r |= 0x7ll << 59;
- return r;
-}
-
-/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should
- either implement VAX arithmetic properly or just signal invalid opcode. */
-
-uint64_t helper_addf (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = f_to_float32(a);
- fb = f_to_float32(b);
- fr = float32_add(fa, fb, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_subf (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = f_to_float32(a);
- fb = f_to_float32(b);
- fr = float32_sub(fa, fb, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_mulf (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = f_to_float32(a);
- fb = f_to_float32(b);
- fr = float32_mul(fa, fb, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_divf (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = f_to_float32(a);
- fb = f_to_float32(b);
- fr = float32_div(fa, fb, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_sqrtf (uint64_t t)
-{
- float32 ft, fr;
-
- ft = f_to_float32(t);
- fr = float32_sqrt(ft, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-
-/* G floating (VAX) */
-static inline uint64_t float64_to_g(float64 fa)
-{
- uint64_t r, exp, mant, sig;
- CPU_DoubleU a;
-
- a.d = fa;
- sig = a.ll & 0x8000000000000000ull;
- exp = (a.ll >> 52) & 0x7ff;
- mant = a.ll & 0x000fffffffffffffull;
-
- if (exp == 2047) {
- /* NaN or infinity */
- r = 1; /* VAX dirty zero */
- } else if (exp == 0) {
- if (mant == 0) {
- /* Zero */
- r = 0;
- } else {
- /* Denormalized */
- r = sig | ((exp + 1) << 52) | mant;
- }
- } else {
- if (exp >= 2045) {
- /* Overflow */
- r = 1; /* VAX dirty zero */
- } else {
- r = sig | ((exp + 2) << 52);
- }
- }
-
- return r;
-}
-
-static inline float64 g_to_float64(uint64_t a)
-{
- uint64_t exp, mant_sig;
- CPU_DoubleU r;
-
- exp = (a >> 52) & 0x7ff;
- mant_sig = a & 0x800fffffffffffffull;
-
- if (!exp && mant_sig) {
- /* Reserved operands / Dirty zero */
- dynamic_excp(env, GETPC(), EXCP_OPCDEC, 0);
- }
-
- if (exp < 3) {
- /* Underflow */
- r.ll = 0;
- } else {
- r.ll = ((exp - 2) << 52) | mant_sig;
- }
-
- return r.d;
-}
-
-uint64_t helper_g_to_memory (uint64_t a)
-{
- uint64_t r;
- r = (a & 0x000000000000ffffull) << 48;
- r |= (a & 0x00000000ffff0000ull) << 16;
- r |= (a & 0x0000ffff00000000ull) >> 16;
- r |= (a & 0xffff000000000000ull) >> 48;
- return r;
-}
-
-uint64_t helper_memory_to_g (uint64_t a)
-{
- uint64_t r;
- r = (a & 0x000000000000ffffull) << 48;
- r |= (a & 0x00000000ffff0000ull) << 16;
- r |= (a & 0x0000ffff00000000ull) >> 16;
- r |= (a & 0xffff000000000000ull) >> 48;
- return r;
-}
-
-uint64_t helper_addg (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
- fr = float64_add(fa, fb, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-uint64_t helper_subg (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
- fr = float64_sub(fa, fb, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-uint64_t helper_mulg (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
- fr = float64_mul(fa, fb, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-uint64_t helper_divg (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
- fr = float64_div(fa, fb, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-uint64_t helper_sqrtg (uint64_t a)
-{
- float64 fa, fr;
-
- fa = g_to_float64(a);
- fr = float64_sqrt(fa, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-
-/* S floating (single) */
-
-/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
-static inline uint64_t float32_to_s_int(uint32_t fi)
-{
- uint32_t frac = fi & 0x7fffff;
- uint32_t sign = fi >> 31;
- uint32_t exp_msb = (fi >> 30) & 1;
- uint32_t exp_low = (fi >> 23) & 0x7f;
- uint32_t exp;
-
- exp = (exp_msb << 10) | exp_low;
- if (exp_msb) {
- if (exp_low == 0x7f)
- exp = 0x7ff;
- } else {
- if (exp_low != 0x00)
- exp |= 0x380;
- }
-
- return (((uint64_t)sign << 63)
- | ((uint64_t)exp << 52)
- | ((uint64_t)frac << 29));
-}
-
-static inline uint64_t float32_to_s(float32 fa)
-{
- CPU_FloatU a;
- a.f = fa;
- return float32_to_s_int(a.l);
-}
-
-static inline uint32_t s_to_float32_int(uint64_t a)
-{
- return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
-}
-
-static inline float32 s_to_float32(uint64_t a)
-{
- CPU_FloatU r;
- r.l = s_to_float32_int(a);
- return r.f;
-}
-
-uint32_t helper_s_to_memory (uint64_t a)
-{
- return s_to_float32_int(a);
-}
-
-uint64_t helper_memory_to_s (uint32_t a)
-{
- return float32_to_s_int(a);
-}
-
-uint64_t helper_adds (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = s_to_float32(a);
- fb = s_to_float32(b);
- fr = float32_add(fa, fb, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_subs (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = s_to_float32(a);
- fb = s_to_float32(b);
- fr = float32_sub(fa, fb, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_muls (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = s_to_float32(a);
- fb = s_to_float32(b);
- fr = float32_mul(fa, fb, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_divs (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = s_to_float32(a);
- fb = s_to_float32(b);
- fr = float32_div(fa, fb, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_sqrts (uint64_t a)
-{
- float32 fa, fr;
-
- fa = s_to_float32(a);
- fr = float32_sqrt(fa, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-
-/* T floating (double) */
-static inline float64 t_to_float64(uint64_t a)
-{
- /* Memory format is the same as float64 */
- CPU_DoubleU r;
- r.ll = a;
- return r.d;
-}
-
-static inline uint64_t float64_to_t(float64 fa)
-{
- /* Memory format is the same as float64 */
- CPU_DoubleU r;
- r.d = fa;
- return r.ll;
-}
-
-uint64_t helper_addt (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
- fr = float64_add(fa, fb, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_subt (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
- fr = float64_sub(fa, fb, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_mult (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
- fr = float64_mul(fa, fb, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_divt (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
- fr = float64_div(fa, fb, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_sqrtt (uint64_t a)
-{
- float64 fa, fr;
-
- fa = t_to_float64(a);
- fr = float64_sqrt(fa, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-/* Comparisons */
-uint64_t helper_cmptun (uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
-
- if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
- return 0x4000000000000000ULL;
- } else {
- return 0;
- }
-}
-
-uint64_t helper_cmpteq(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
-
- if (float64_eq_quiet(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmptle(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
-
- if (float64_le(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmptlt(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
-
- if (float64_lt(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmpgeq(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
-
- if (float64_eq_quiet(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmpgle(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
-
- if (float64_le(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmpglt(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
-
- if (float64_lt(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-/* Floating point format conversion */
-uint64_t helper_cvtts (uint64_t a)
-{
- float64 fa;
- float32 fr;
-
- fa = t_to_float64(a);
- fr = float64_to_float32(fa, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_cvtst (uint64_t a)
-{
- float32 fa;
- float64 fr;
-
- fa = s_to_float32(a);
- fr = float32_to_float64(fa, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_cvtqs (uint64_t a)
-{
- float32 fr = int64_to_float32(a, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-/* Implement float64 to uint64 conversion without saturation -- we must
- supply the truncated result. This behaviour is used by the compiler
- to get unsigned conversion for free with the same instruction.
-
- The VI flag is set when overflow or inexact exceptions should be raised. */
-
-static inline uint64_t helper_cvttq_internal(uint64_t a, int roundmode, int VI)
-{
- uint64_t frac, ret = 0;
- uint32_t exp, sign, exc = 0;
- int shift;
-
- sign = (a >> 63);
- exp = (uint32_t)(a >> 52) & 0x7ff;
- frac = a & 0xfffffffffffffull;
-
- if (exp == 0) {
- if (unlikely(frac != 0)) {
- goto do_underflow;
- }
- } else if (exp == 0x7ff) {
- exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0);
- } else {
- /* Restore implicit bit. */
- frac |= 0x10000000000000ull;
-
- shift = exp - 1023 - 52;
- if (shift >= 0) {
- /* In this case the number is so large that we must shift
- the fraction left. There is no rounding to do. */
- if (shift < 63) {
- ret = frac << shift;
- if (VI && (ret >> shift) != frac) {
- exc = float_flag_overflow;
- }
- }
- } else {
- uint64_t round;
-
- /* In this case the number is smaller than the fraction as
- represented by the 52 bit number. Here we must think
- about rounding the result. Handle this by shifting the
- fractional part of the number into the high bits of ROUND.
- This will let us efficiently handle round-to-nearest. */
- shift = -shift;
- if (shift < 63) {
- ret = frac >> shift;
- round = frac << (64 - shift);
- } else {
- /* The exponent is so small we shift out everything.
- Leave a sticky bit for proper rounding below. */
- do_underflow:
- round = 1;
- }
-
- if (round) {
- exc = (VI ? float_flag_inexact : 0);
- switch (roundmode) {
- case float_round_nearest_even:
- if (round == (1ull << 63)) {
- /* Fraction is exactly 0.5; round to even. */
- ret += (ret & 1);
- } else if (round > (1ull << 63)) {
- ret += 1;
- }
- break;
- case float_round_to_zero:
- break;
- case float_round_up:
- ret += 1 - sign;
- break;
- case float_round_down:
- ret += sign;
- break;
- }
- }
- }
- if (sign) {
- ret = -ret;
- }
- }
- if (unlikely(exc)) {
- float_raise(exc, &FP_STATUS);
- }
-
- return ret;
-}
-
-uint64_t helper_cvttq(uint64_t a)
-{
- return helper_cvttq_internal(a, FP_STATUS.float_rounding_mode, 1);
-}
-
-uint64_t helper_cvttq_c(uint64_t a)
-{
- return helper_cvttq_internal(a, float_round_to_zero, 0);
-}
-
-uint64_t helper_cvttq_svic(uint64_t a)
-{
- return helper_cvttq_internal(a, float_round_to_zero, 1);
-}
-
-uint64_t helper_cvtqt (uint64_t a)
-{
- float64 fr = int64_to_float64(a, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_cvtqf (uint64_t a)
-{
- float32 fr = int64_to_float32(a, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_cvtgf (uint64_t a)
-{
- float64 fa;
- float32 fr;
-
- fa = g_to_float64(a);
- fr = float64_to_float32(fa, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_cvtgq (uint64_t a)
-{
- float64 fa = g_to_float64(a);
- return float64_to_int64_round_to_zero(fa, &FP_STATUS);
-}
-
-uint64_t helper_cvtqg (uint64_t a)
-{
- float64 fr;
- fr = int64_to_float64(a, &FP_STATUS);
- return float64_to_g(fr);
-}
-
/* PALcode support special instructions */
#if !defined (CONFIG_USER_ONLY)
void helper_hw_ret (uint64_t a)
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 0c06b55..a9b97a3 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -611,7 +611,8 @@ static void gen_qual_roundmode(DisasContext *ctx, int fn11)
tcg_gen_movi_i32(tmp, float_round_down);
break;
case QUAL_RM_D:
- tcg_gen_ld8u_i32(tmp, cpu_env, offsetof(CPUAlphaState, fpcr_dyn_round));
+ tcg_gen_ld8u_i32(tmp, cpu_env,
+ offsetof(CPUAlphaState, fpcr_dyn_round));
break;
}
@@ -641,7 +642,8 @@ static void gen_qual_flushzero(DisasContext *ctx, int fn11)
tmp = tcg_temp_new_i32();
if (fn11) {
/* Underflow is enabled, use the FPCR setting. */
- tcg_gen_ld8u_i32(tmp, cpu_env, offsetof(CPUAlphaState, fpcr_flush_to_zero));
+ tcg_gen_ld8u_i32(tmp, cpu_env,
+ offsetof(CPUAlphaState, fpcr_flush_to_zero));
} else {
/* Underflow is disabled, force flush-to-zero. */
tcg_gen_movi_i32(tmp, 1);
@@ -663,11 +665,11 @@ static TCGv gen_ieee_input(int reg, int fn11, int is_cmp)
if (reg == 31) {
tcg_gen_movi_i64(val, 0);
} else if (fn11 & QUAL_S) {
- gen_helper_ieee_input_s(val, cpu_fir[reg]);
+ gen_helper_ieee_input_s(val, cpu_env, cpu_fir[reg]);
} else if (is_cmp) {
- gen_helper_ieee_input_cmp(val, cpu_fir[reg]);
+ gen_helper_ieee_input_cmp(val, cpu_env, cpu_fir[reg]);
} else {
- gen_helper_ieee_input(val, cpu_fir[reg]);
+ gen_helper_ieee_input(val, cpu_env, cpu_fir[reg]);
}
return val;
}
@@ -680,7 +682,7 @@ static void gen_fp_exc_clear(void)
offsetof(CPUAlphaState, fp_status.float_exception_flags));
tcg_temp_free_i32(zero);
#else
- gen_helper_fp_exc_clear();
+ gen_helper_fp_exc_clear(cpu_env);
#endif
}
@@ -698,7 +700,7 @@ static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
tcg_gen_ld8u_i32(exc, cpu_env,
offsetof(CPUAlphaState, fp_status.float_exception_flags));
#else
- gen_helper_fp_exc_get(exc);
+ gen_helper_fp_exc_get(exc, cpu_env);
#endif
if (ignore) {
@@ -713,9 +715,9 @@ static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
reg = tcg_const_i32(rc + 32);
if (fn11 & QUAL_S) {
- gen_helper_fp_exc_raise_s(exc, reg);
+ gen_helper_fp_exc_raise_s(cpu_env, exc, reg);
} else {
- gen_helper_fp_exc_raise(exc, reg);
+ gen_helper_fp_exc_raise(cpu_env, exc, reg);
}
tcg_temp_free_i32(reg);
@@ -784,20 +786,20 @@ static void gen_fcvtql_v(DisasContext *ctx, int rb, int rc)
gen_fcvtql(rb, rc);
}
-#define FARITH2(name) \
-static inline void glue(gen_f, name)(int rb, int rc) \
-{ \
- if (unlikely(rc == 31)) { \
- return; \
- } \
- if (rb != 31) { \
- gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]); \
- } else { \
- TCGv tmp = tcg_const_i64(0); \
- gen_helper_ ## name (cpu_fir[rc], tmp); \
- tcg_temp_free(tmp); \
- } \
-}
+#define FARITH2(name) \
+ static inline void glue(gen_f, name)(int rb, int rc) \
+ { \
+ if (unlikely(rc == 31)) { \
+ return; \
+ } \
+ if (rb != 31) { \
+ gen_helper_ ## name(cpu_fir[rc], cpu_env, cpu_fir[rb]); \
+ } else { \
+ TCGv tmp = tcg_const_i64(0); \
+ gen_helper_ ## name(cpu_fir[rc], cpu_env, tmp); \
+ tcg_temp_free(tmp); \
+ } \
+ }
/* ??? VAX instruction qualifiers ignored. */
FARITH2(sqrtf)
@@ -807,7 +809,8 @@ FARITH2(cvtgq)
FARITH2(cvtqf)
FARITH2(cvtqg)
-static void gen_ieee_arith2(DisasContext *ctx, void (*helper)(TCGv, TCGv),
+static void gen_ieee_arith2(DisasContext *ctx,
+ void (*helper)(TCGv, TCGv_ptr, TCGv),
int rb, int rc, int fn11)
{
TCGv vb;
@@ -823,7 +826,7 @@ static void gen_ieee_arith2(DisasContext *ctx, void (*helper)(TCGv, TCGv),
gen_fp_exc_clear();
vb = gen_ieee_input(rb, fn11, 0);
- helper(cpu_fir[rc], vb);
+ helper(cpu_fir[rc], cpu_env, vb);
tcg_temp_free(vb);
gen_fp_exc_raise(rc, fn11);
@@ -859,18 +862,18 @@ static void gen_fcvttq(DisasContext *ctx, int rb, int rc, int fn11)
also do not have integer overflow enabled. Special case that. */
switch (fn11) {
case QUAL_RM_C:
- gen_helper_cvttq_c(cpu_fir[rc], vb);
+ gen_helper_cvttq_c(cpu_fir[rc], cpu_env, vb);
break;
case QUAL_V | QUAL_RM_C:
case QUAL_S | QUAL_V | QUAL_RM_C:
ignore = float_flag_inexact;
/* FALLTHRU */
case QUAL_S | QUAL_V | QUAL_I | QUAL_RM_C:
- gen_helper_cvttq_svic(cpu_fir[rc], vb);
+ gen_helper_cvttq_svic(cpu_fir[rc], cpu_env, vb);
break;
default:
gen_qual_roundmode(ctx, fn11);
- gen_helper_cvttq(cpu_fir[rc], vb);
+ gen_helper_cvttq(cpu_fir[rc], cpu_env, vb);
ignore |= (fn11 & QUAL_V ? 0 : float_flag_overflow);
ignore |= (fn11 & QUAL_I ? 0 : float_flag_inexact);
break;
@@ -880,7 +883,8 @@ static void gen_fcvttq(DisasContext *ctx, int rb, int rc, int fn11)
gen_fp_exc_raise_ignore(rc, fn11, ignore);
}
-static void gen_ieee_intcvt(DisasContext *ctx, void (*helper)(TCGv, TCGv),
+static void gen_ieee_intcvt(DisasContext *ctx,
+ void (*helper)(TCGv, TCGv_ptr, TCGv),
int rb, int rc, int fn11)
{
TCGv vb;
@@ -904,10 +908,10 @@ static void gen_ieee_intcvt(DisasContext *ctx, void (*helper)(TCGv, TCGv),
inexact handling is requested. */
if (fn11 & QUAL_I) {
gen_fp_exc_clear();
- helper(cpu_fir[rc], vb);
+ helper(cpu_fir[rc], cpu_env, vb);
gen_fp_exc_raise(rc, fn11);
} else {
- helper(cpu_fir[rc], vb);
+ helper(cpu_fir[rc], cpu_env, vb);
}
if (rb == 31) {
@@ -999,34 +1003,34 @@ static inline void gen_fcpyse(int ra, int rb, int rc)
gen_cpys_internal(ra, rb, rc, 0, 0xFFF0000000000000ULL);
}
-#define FARITH3(name) \
-static inline void glue(gen_f, name)(int ra, int rb, int rc) \
-{ \
- TCGv va, vb; \
- \
- if (unlikely(rc == 31)) { \
- return; \
- } \
- if (ra == 31) { \
- va = tcg_const_i64(0); \
- } else { \
- va = cpu_fir[ra]; \
- } \
- if (rb == 31) { \
- vb = tcg_const_i64(0); \
- } else { \
- vb = cpu_fir[rb]; \
- } \
- \
- gen_helper_ ## name (cpu_fir[rc], va, vb); \
- \
- if (ra == 31) { \
- tcg_temp_free(va); \
- } \
- if (rb == 31) { \
- tcg_temp_free(vb); \
- } \
-}
+#define FARITH3(name) \
+ static inline void glue(gen_f, name)(int ra, int rb, int rc) \
+ { \
+ TCGv va, vb; \
+ \
+ if (unlikely(rc == 31)) { \
+ return; \
+ } \
+ if (ra == 31) { \
+ va = tcg_const_i64(0); \
+ } else { \
+ va = cpu_fir[ra]; \
+ } \
+ if (rb == 31) { \
+ vb = tcg_const_i64(0); \
+ } else { \
+ vb = cpu_fir[rb]; \
+ } \
+ \
+ gen_helper_ ## name(cpu_fir[rc], cpu_env, va, vb); \
+ \
+ if (ra == 31) { \
+ tcg_temp_free(va); \
+ } \
+ if (rb == 31) { \
+ tcg_temp_free(vb); \
+ } \
+ }
/* ??? VAX instruction qualifiers ignored. */
FARITH3(addf)
@@ -1042,7 +1046,7 @@ FARITH3(cmpglt)
FARITH3(cmpgle)
static void gen_ieee_arith3(DisasContext *ctx,
- void (*helper)(TCGv, TCGv, TCGv),
+ void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv),
int ra, int rb, int rc, int fn11)
{
TCGv va, vb;
@@ -1059,7 +1063,7 @@ static void gen_ieee_arith3(DisasContext *ctx,
va = gen_ieee_input(ra, fn11, 0);
vb = gen_ieee_input(rb, fn11, 0);
- helper(cpu_fir[rc], va, vb);
+ helper(cpu_fir[rc], cpu_env, va, vb);
tcg_temp_free(va);
tcg_temp_free(vb);
@@ -1082,7 +1086,7 @@ IEEE_ARITH3(mult)
IEEE_ARITH3(divt)
static void gen_ieee_compare(DisasContext *ctx,
- void (*helper)(TCGv, TCGv, TCGv),
+ void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv),
int ra, int rb, int rc, int fn11)
{
TCGv va, vb;
@@ -1097,7 +1101,7 @@ static void gen_ieee_compare(DisasContext *ctx,
va = gen_ieee_input(ra, fn11, 1);
vb = gen_ieee_input(rb, fn11, 1);
- helper(cpu_fir[rc], va, vb);
+ helper(cpu_fir[rc], cpu_env, va, vb);
tcg_temp_free(va);
tcg_temp_free(vb);
commit b9f0923eb782b92a85657092b625d96b0af26e2e
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:08 2012 -0700
target-alpha: Move exception helpers to helper.c.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 48c0fdc..c7787f6 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -434,6 +434,9 @@ int cpu_alpha_handle_mmu_fault (CPUAlphaState *env, uint64_t address, int rw,
int mmu_idx);
#define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
void do_interrupt (CPUAlphaState *env);
+void do_restore_state(CPUAlphaState *, void *retaddr);
+void QEMU_NORETURN dynamic_excp(CPUAlphaState *, void *, int, int);
+void QEMU_NORETURN arith_excp(CPUAlphaState *, void *, int, uint64_t);
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env);
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val);
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 3f2e7c3..584457f 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -23,6 +23,7 @@
#include "cpu.h"
#include "softfloat.h"
+#include "helper.h"
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
{
@@ -484,3 +485,41 @@ void cpu_dump_state (CPUAlphaState *env, FILE *f, fprintf_function cpu_fprintf,
}
cpu_fprintf(f, "\n");
}
+
+void do_restore_state(CPUAlphaState *env, void *retaddr)
+{
+ uintptr_t pc = (uintptr_t)retaddr;
+ if (pc) {
+ TranslationBlock *tb = tb_find_pc(pc);
+ if (tb) {
+ cpu_restore_state(tb, env, pc);
+ }
+ }
+}
+
+/* This should only be called from translate, via gen_excp.
+ We expect that ENV->PC has already been updated. */
+void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
+{
+ env->exception_index = excp;
+ env->error_code = error;
+ cpu_loop_exit(env);
+}
+
+/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
+void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, void *retaddr,
+ int excp, int error)
+{
+ env->exception_index = excp;
+ env->error_code = error;
+ do_restore_state(env, retaddr);
+ cpu_loop_exit(env);
+}
+
+void QEMU_NORETURN arith_excp(CPUAlphaState *env, void *retaddr,
+ int exc, uint64_t mask)
+{
+ env->trap_arg0 = exc;
+ env->trap_arg1 = mask;
+ dynamic_excp(env, retaddr, EXCP_ARITH, 0);
+}
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index b693cee..91a9e39 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -1,6 +1,6 @@
#include "def-helper.h"
-DEF_HELPER_2(excp, void, int, int)
+DEF_HELPER_3(excp, void, env, int, int)
DEF_HELPER_FLAGS_0(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64)
DEF_HELPER_2(addqv, i64, i64, i64)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index eab7a82..af5fa82 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -30,43 +30,6 @@
/*****************************************************************************/
/* Exceptions processing helpers */
-/* This should only be called from translate, via gen_excp.
- We expect that ENV->PC has already been updated. */
-void QEMU_NORETURN helper_excp(int excp, int error)
-{
- env->exception_index = excp;
- env->error_code = error;
- cpu_loop_exit(env);
-}
-
-static void do_restore_state(void *retaddr)
-{
- unsigned long pc = (unsigned long)retaddr;
-
- if (pc) {
- TranslationBlock *tb = tb_find_pc(pc);
- if (tb) {
- cpu_restore_state(tb, env, pc);
- }
- }
-}
-
-/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
-static void QEMU_NORETURN dynamic_excp(int excp, int error)
-{
- env->exception_index = excp;
- env->error_code = error;
- do_restore_state(GETPC());
- cpu_loop_exit(env);
-}
-
-static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
-{
- env->trap_arg0 = exc;
- env->trap_arg1 = mask;
- dynamic_excp(EXCP_ARITH, 0);
-}
-
uint64_t helper_load_pcc (void)
{
#ifndef CONFIG_USER_ONLY
@@ -97,7 +60,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 += op2;
if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
- arith_excp(EXC_M_IOV, 0);
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return op1;
}
@@ -107,7 +70,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 = (uint32_t)(op1 + op2);
if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
- arith_excp(EXC_M_IOV, 0);
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return op1;
}
@@ -117,7 +80,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2)
uint64_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
- arith_excp(EXC_M_IOV, 0);
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return res;
}
@@ -127,7 +90,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2)
uint32_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
- arith_excp(EXC_M_IOV, 0);
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return res;
}
@@ -137,7 +100,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2)
int64_t res = (int64_t)op1 * (int64_t)op2;
if (unlikely((int32_t)res != res)) {
- arith_excp(EXC_M_IOV, 0);
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return (int64_t)((int32_t)res);
}
@@ -149,7 +112,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
muls64(&tl, &th, op1, op2);
/* If th != 0 && th != -1, then we had an overflow */
if (unlikely((th + 1) > 1)) {
- arith_excp(EXC_M_IOV, 0);
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return tl;
}
@@ -200,7 +163,7 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
hw_exc |= EXC_M_INE;
}
- arith_excp(hw_exc, 1ull << regno);
+ arith_excp(env, GETPC(), hw_exc, 1ull << regno);
}
}
@@ -230,7 +193,7 @@ uint64_t helper_ieee_input(uint64_t val)
if (env->fpcr_dnz) {
val &= 1ull << 63;
} else {
- arith_excp(EXC_M_UNF, 0);
+ arith_excp(env, GETPC(), EXC_M_UNF, 0);
}
}
} else if (exp == 0x7ff) {
@@ -238,7 +201,7 @@ uint64_t helper_ieee_input(uint64_t val)
/* ??? I'm not sure these exception bit flags are correct. I do
know that the Linux kernel, at least, doesn't rely on them and
just emulates the insn to figure out what exception to use. */
- arith_excp(frac ? EXC_M_INV : EXC_M_FOV, 0);
+ arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
}
return val;
}
@@ -255,12 +218,12 @@ uint64_t helper_ieee_input_cmp(uint64_t val)
if (env->fpcr_dnz) {
val &= 1ull << 63;
} else {
- arith_excp(EXC_M_UNF, 0);
+ arith_excp(env, GETPC(), EXC_M_UNF, 0);
}
}
} else if (exp == 0x7ff && frac) {
/* NaN. */
- arith_excp(EXC_M_INV, 0);
+ arith_excp(env, GETPC(), EXC_M_INV, 0);
}
return val;
}
@@ -323,7 +286,7 @@ static inline float32 f_to_float32(uint64_t a)
if (unlikely(!exp && mant_sig)) {
/* Reserved operands / Dirty zero */
- dynamic_excp(EXCP_OPCDEC, 0);
+ dynamic_excp(env, GETPC(), EXCP_OPCDEC, 0);
}
if (exp < 3) {
@@ -453,7 +416,7 @@ static inline float64 g_to_float64(uint64_t a)
if (!exp && mant_sig) {
/* Reserved operands / Dirty zero */
- dynamic_excp(EXCP_OPCDEC, 0);
+ dynamic_excp(env, GETPC(), EXCP_OPCDEC, 0);
}
if (exp < 3) {
@@ -1085,7 +1048,7 @@ static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
uint64_t pc;
uint32_t insn;
- do_restore_state(retaddr);
+ do_restore_state(env, retaddr);
pc = env->pc;
insn = ldl_code(pc);
@@ -1093,7 +1056,9 @@ static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
env->trap_arg0 = addr;
env->trap_arg1 = insn >> 26; /* opcode */
env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
- helper_excp(EXCP_UNALIGN, 0);
+ env->exception_index = EXCP_UNALIGN;
+ env->error_code = 0;
+ cpu_loop_exit(env);
}
void QEMU_NORETURN cpu_unassigned_access(CPUAlphaState *env1,
@@ -1103,7 +1068,7 @@ void QEMU_NORETURN cpu_unassigned_access(CPUAlphaState *env1,
env = env1;
env->trap_arg0 = addr;
env->trap_arg1 = is_write;
- dynamic_excp(EXCP_MCHK, 0);
+ dynamic_excp(env1, GETPC(), EXCP_MCHK, 0);
}
#include "softmmu_exec.h"
@@ -1137,7 +1102,7 @@ void tlb_fill(CPUAlphaState *env1, target_ulong addr, int is_write, int mmu_idx,
env = env1;
ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (unlikely(ret != 0)) {
- do_restore_state(retaddr);
+ do_restore_state(env, retaddr);
/* Exception index and error code are already set */
cpu_loop_exit(env);
}
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 2c24619..0c06b55 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -149,7 +149,7 @@ static void gen_excp_1(int exception, int error_code)
tmp1 = tcg_const_i32(exception);
tmp2 = tcg_const_i32(error_code);
- gen_helper_excp(tmp1, tmp2);
+ gen_helper_excp(cpu_env, tmp1, tmp2);
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp1);
}
commit 0be034bc2cc0e06584ee368759c47e5efa1439e7
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:07 2012 -0700
target-alpha: Move integer helpers to int_helper.c.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile.target b/Makefile.target
index 63cf769..ddeb7e0 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -96,6 +96,7 @@ libobj-y += cpu_init.o
endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
+libobj-$(TARGET_ALPHA) += int_helper.o
libobj-y += disas.o
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
diff --git a/target-alpha/int_helper.c b/target-alpha/int_helper.c
new file mode 100644
index 0000000..79c0cfe
--- /dev/null
+++ b/target-alpha/int_helper.c
@@ -0,0 +1,257 @@
+/*
+ * Helpers for integer and multimedia instructions.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "host-utils.h"
+
+
+uint64_t helper_umulh(uint64_t op1, uint64_t op2)
+{
+ uint64_t tl, th;
+ mulu64(&tl, &th, op1, op2);
+ return th;
+}
+
+uint64_t helper_ctpop(uint64_t arg)
+{
+ return ctpop64(arg);
+}
+
+uint64_t helper_ctlz(uint64_t arg)
+{
+ return clz64(arg);
+}
+
+uint64_t helper_cttz(uint64_t arg)
+{
+ return ctz64(arg);
+}
+
+static inline uint64_t byte_zap(uint64_t op, uint8_t mskb)
+{
+ uint64_t mask;
+
+ mask = 0;
+ mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL;
+ mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL;
+ mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL;
+ mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL;
+ mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL;
+ mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL;
+ mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL;
+ mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL;
+
+ return op & ~mask;
+}
+
+uint64_t helper_zap(uint64_t val, uint64_t mask)
+{
+ return byte_zap(val, mask);
+}
+
+uint64_t helper_zapnot(uint64_t val, uint64_t mask)
+{
+ return byte_zap(val, ~mask);
+}
+
+uint64_t helper_cmpbge(uint64_t op1, uint64_t op2)
+{
+ uint8_t opa, opb, res;
+ int i;
+
+ res = 0;
+ for (i = 0; i < 8; i++) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ if (opa >= opb) {
+ res |= 1 << i;
+ }
+ }
+ return res;
+}
+
+uint64_t helper_minub8(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint8_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ opr = opa < opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 8);
+ }
+ return res;
+}
+
+uint64_t helper_minsb8(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ int8_t opa, opb;
+ uint8_t opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ opr = opa < opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 8);
+ }
+ return res;
+}
+
+uint64_t helper_minuw4(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint16_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ opa = op1 >> (i * 16);
+ opb = op2 >> (i * 16);
+ opr = opa < opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 16);
+ }
+ return res;
+}
+
+uint64_t helper_minsw4(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ int16_t opa, opb;
+ uint16_t opr;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ opa = op1 >> (i * 16);
+ opb = op2 >> (i * 16);
+ opr = opa < opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 16);
+ }
+ return res;
+}
+
+uint64_t helper_maxub8(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint8_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ opr = opa > opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 8);
+ }
+ return res;
+}
+
+uint64_t helper_maxsb8(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ int8_t opa, opb;
+ uint8_t opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ opr = opa > opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 8);
+ }
+ return res;
+}
+
+uint64_t helper_maxuw4(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint16_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ opa = op1 >> (i * 16);
+ opb = op2 >> (i * 16);
+ opr = opa > opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 16);
+ }
+ return res;
+}
+
+uint64_t helper_maxsw4(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ int16_t opa, opb;
+ uint16_t opr;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ opa = op1 >> (i * 16);
+ opb = op2 >> (i * 16);
+ opr = opa > opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 16);
+ }
+ return res;
+}
+
+uint64_t helper_perr(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint8_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ if (opa >= opb) {
+ opr = opa - opb;
+ } else {
+ opr = opb - opa;
+ }
+ res += opr;
+ }
+ return res;
+}
+
+uint64_t helper_pklb(uint64_t op1)
+{
+ return (op1 & 0xff) | ((op1 >> 24) & 0xff00);
+}
+
+uint64_t helper_pkwb(uint64_t op1)
+{
+ return ((op1 & 0xff)
+ | ((op1 >> 8) & 0xff00)
+ | ((op1 >> 16) & 0xff0000)
+ | ((op1 >> 24) & 0xff000000));
+}
+
+uint64_t helper_unpkbl(uint64_t op1)
+{
+ return (op1 & 0xff) | ((op1 & 0xff00) << 24);
+}
+
+uint64_t helper_unpkbw(uint64_t op1)
+{
+ return ((op1 & 0xff)
+ | ((op1 & 0xff00) << 8)
+ | ((op1 & 0xff0000) << 16)
+ | ((op1 & 0xff000000) << 24));
+}
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index c77f009..eab7a82 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -154,239 +154,6 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
return tl;
}
-uint64_t helper_umulh (uint64_t op1, uint64_t op2)
-{
- uint64_t tl, th;
-
- mulu64(&tl, &th, op1, op2);
- return th;
-}
-
-uint64_t helper_ctpop (uint64_t arg)
-{
- return ctpop64(arg);
-}
-
-uint64_t helper_ctlz (uint64_t arg)
-{
- return clz64(arg);
-}
-
-uint64_t helper_cttz (uint64_t arg)
-{
- return ctz64(arg);
-}
-
-static inline uint64_t byte_zap(uint64_t op, uint8_t mskb)
-{
- uint64_t mask;
-
- mask = 0;
- mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL;
- mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL;
- mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL;
- mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL;
- mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL;
- mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL;
- mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL;
- mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL;
-
- return op & ~mask;
-}
-
-uint64_t helper_zap(uint64_t val, uint64_t mask)
-{
- return byte_zap(val, mask);
-}
-
-uint64_t helper_zapnot(uint64_t val, uint64_t mask)
-{
- return byte_zap(val, ~mask);
-}
-
-uint64_t helper_cmpbge (uint64_t op1, uint64_t op2)
-{
- uint8_t opa, opb, res;
- int i;
-
- res = 0;
- for (i = 0; i < 8; i++) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- if (opa >= opb)
- res |= 1 << i;
- }
- return res;
-}
-
-uint64_t helper_minub8 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint8_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- opr = opa < opb ? opa : opb;
- res |= (uint64_t)opr << (i * 8);
- }
- return res;
-}
-
-uint64_t helper_minsb8 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- int8_t opa, opb;
- uint8_t opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- opr = opa < opb ? opa : opb;
- res |= (uint64_t)opr << (i * 8);
- }
- return res;
-}
-
-uint64_t helper_minuw4 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint16_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 4; ++i) {
- opa = op1 >> (i * 16);
- opb = op2 >> (i * 16);
- opr = opa < opb ? opa : opb;
- res |= (uint64_t)opr << (i * 16);
- }
- return res;
-}
-
-uint64_t helper_minsw4 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- int16_t opa, opb;
- uint16_t opr;
- int i;
-
- for (i = 0; i < 4; ++i) {
- opa = op1 >> (i * 16);
- opb = op2 >> (i * 16);
- opr = opa < opb ? opa : opb;
- res |= (uint64_t)opr << (i * 16);
- }
- return res;
-}
-
-uint64_t helper_maxub8 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint8_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- opr = opa > opb ? opa : opb;
- res |= (uint64_t)opr << (i * 8);
- }
- return res;
-}
-
-uint64_t helper_maxsb8 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- int8_t opa, opb;
- uint8_t opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- opr = opa > opb ? opa : opb;
- res |= (uint64_t)opr << (i * 8);
- }
- return res;
-}
-
-uint64_t helper_maxuw4 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint16_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 4; ++i) {
- opa = op1 >> (i * 16);
- opb = op2 >> (i * 16);
- opr = opa > opb ? opa : opb;
- res |= (uint64_t)opr << (i * 16);
- }
- return res;
-}
-
-uint64_t helper_maxsw4 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- int16_t opa, opb;
- uint16_t opr;
- int i;
-
- for (i = 0; i < 4; ++i) {
- opa = op1 >> (i * 16);
- opb = op2 >> (i * 16);
- opr = opa > opb ? opa : opb;
- res |= (uint64_t)opr << (i * 16);
- }
- return res;
-}
-
-uint64_t helper_perr (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint8_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- if (opa >= opb)
- opr = opa - opb;
- else
- opr = opb - opa;
- res += opr;
- }
- return res;
-}
-
-uint64_t helper_pklb (uint64_t op1)
-{
- return (op1 & 0xff) | ((op1 >> 24) & 0xff00);
-}
-
-uint64_t helper_pkwb (uint64_t op1)
-{
- return ((op1 & 0xff)
- | ((op1 >> 8) & 0xff00)
- | ((op1 >> 16) & 0xff0000)
- | ((op1 >> 24) & 0xff000000));
-}
-
-uint64_t helper_unpkbl (uint64_t op1)
-{
- return (op1 & 0xff) | ((op1 & 0xff00) << 24);
-}
-
-uint64_t helper_unpkbw (uint64_t op1)
-{
- return ((op1 & 0xff)
- | ((op1 & 0xff00) << 8)
- | ((op1 & 0xff0000) << 16)
- | ((op1 & 0xff000000) << 24));
-}
-
/* Floating point helpers */
void helper_setroundmode (uint32_t val)
commit 7b74505331fdd701557b01dd09ae9a62f31ea994
Author: Richard Henderson <rth at twiddle.net>
Date: Sat Mar 24 09:51:06 2012 -0700
alpha-linux-user: Initialize fpu to round-to-normal.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index b51fe5c..2c24619 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -3513,7 +3513,8 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
#if defined (CONFIG_USER_ONLY)
env->ps = PS_USER_MODE;
cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
- | FPCR_UNFD | FPCR_INED | FPCR_DNOD));
+ | FPCR_UNFD | FPCR_INED | FPCR_DNOD
+ | FPCR_DYN_NORMAL));
#endif
env->lock_addr = -1;
env->fen = 1;
commit cdb432b2020d3a5b22a7c06278088ccc7d1b2843
Author: Meador Inge <meadori at codesourcery.com>
Date: Thu Mar 15 17:49:45 2012 +0000
gdbserver: Don't send a GDB syscall until the system CPU is stopped
Fix an issue where the GDB server implementation was sending GDB syscall
requests while the system CPU was still running. Syscall requests must
be sent while the CPU is stopped otherwise replies from the GDB client
might get dropped and the GDB server might be incorrectly transitioned
into a 'RUN_STATE_PAUSED' state.
Signed-off-by: Meador Inge <meadori at codesourcery.com>
[PMM: trivial rebase, reinstated comma after last item in RSState enum]
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/gdbstub.c b/gdbstub.c
index f4e97f7..6a7e2c4 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -284,7 +284,6 @@ enum RSState {
RS_GETLINE,
RS_CHKSUM1,
RS_CHKSUM2,
- RS_SYSCALL,
};
typedef struct GDBState {
CPUArchState *c_cpu; /* current CPU for step/continue ops */
@@ -304,6 +303,8 @@ typedef struct GDBState {
CharDriverState *chr;
CharDriverState *mon_chr;
#endif
+ char syscall_buf[256];
+ gdb_syscall_complete_cb current_syscall_cb;
} GDBState;
/* By default use no IRQs and no timers while single stepping so as to
@@ -346,8 +347,6 @@ static int get_char(GDBState *s)
}
#endif
-static gdb_syscall_complete_cb gdb_current_syscall_cb;
-
static enum {
GDB_SYS_UNKNOWN,
GDB_SYS_ENABLED,
@@ -2097,8 +2096,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
if (*p == ',')
p++;
type = *p;
- if (gdb_current_syscall_cb)
- gdb_current_syscall_cb(s->c_cpu, ret, err);
+ if (s->current_syscall_cb) {
+ s->current_syscall_cb(s->c_cpu, ret, err);
+ s->current_syscall_cb = NULL;
+ }
if (type == 'C') {
put_packet(s, "T02");
} else {
@@ -2398,7 +2399,12 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
const char *type;
int ret;
- if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
+ if (running || s->state == RS_INACTIVE) {
+ return;
+ }
+ /* Is there a GDB syscall waiting to be sent? */
+ if (s->current_syscall_cb) {
+ put_packet(s, s->syscall_buf);
return;
}
switch (state) {
@@ -2468,8 +2474,8 @@ send_packet:
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
{
va_list va;
- char buf[256];
char *p;
+ char *p_end;
target_ulong addr;
uint64_t i64;
GDBState *s;
@@ -2477,14 +2483,13 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
s = gdbserver_state;
if (!s)
return;
- gdb_current_syscall_cb = cb;
- s->state = RS_SYSCALL;
+ s->current_syscall_cb = cb;
#ifndef CONFIG_USER_ONLY
vm_stop(RUN_STATE_DEBUG);
#endif
- s->state = RS_IDLE;
va_start(va, fmt);
- p = buf;
+ p = s->syscall_buf;
+ p_end = &s->syscall_buf[sizeof(s->syscall_buf)];
*(p++) = 'F';
while (*fmt) {
if (*fmt == '%') {
@@ -2492,17 +2497,17 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
switch (*fmt++) {
case 'x':
addr = va_arg(va, target_ulong);
- p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx, addr);
+ p += snprintf(p, p_end - p, TARGET_FMT_lx, addr);
break;
case 'l':
if (*(fmt++) != 'x')
goto bad_format;
i64 = va_arg(va, uint64_t);
- p += snprintf(p, &buf[sizeof(buf)] - p, "%" PRIx64, i64);
+ p += snprintf(p, p_end - p, "%" PRIx64, i64);
break;
case 's':
addr = va_arg(va, target_ulong);
- p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx "/%x",
+ p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x",
addr, va_arg(va, int));
break;
default:
@@ -2517,10 +2522,16 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
}
*p = 0;
va_end(va);
- put_packet(s, buf);
#ifdef CONFIG_USER_ONLY
+ put_packet(s, s->syscall_buf);
gdb_handlesig(s->c_cpu, 0);
#else
+ /* In this case wait to send the syscall packet until notification that
+ the CPU has stopped. This must be done because if the packet is sent
+ now the reply from the syscall request could be received while the CPU
+ is still in the running state, which can cause packets to be dropped
+ and state transition 'T' packets to be sent while the syscall is still
+ being processed. */
cpu_exit(s->c_cpu);
#endif
}
@@ -2919,6 +2930,7 @@ int gdbserver_start(const char *device)
s->chr = chr;
s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr;
+ s->current_syscall_cb = NULL;
return 0;
}
commit 3179d694a8dcaa091131e3db644d445c0130713e
Author: Michael Tokarev <mjt at tls.msk.ru>
Date: Tue Mar 20 02:25:57 2012 +0400
Support utf8 chars in pod docs
We've at least one UTF8 char in the qemu texi doc:
$ grep Tibor qemu-doc.texi
by Tibor "TS" Schütz.
$ man ./qemu.1 | grep Tibor
by Tibor "TS" SchA~Xtz.
This patch allows utf8 in man/pod docs.
Initially it was split into two parts and sent on 2012-02-02.
Resending it again (3rd time) now in merged form. If any
other generalizations of $(POD2MAN) are needed it can be done
in a separate patch. Current form of $(POD2MAN) is choosen
to be able to easily change it if some implementation does
not support utf8 or resulting output has issues with local
man(1) program/macros.
First, add @documentencoding in scripts/texi2pod.pl:
Currently our texi2pod ignores @documentencoding even if it is set
properly in *.texi files. This results in a mojibake in documents
generated from qemu.pod (which is generated from qemu-doc.texi by
texi2pod), because the rest of the tools assumes ASCII encoding.
This patch recognizes first @documentencoding in input and places
it at the beginning of output as =encoding directive.
Second, run pod2man with --utf8 option to enable utf8 in manpages:
This option makes no difference for manpages which contains only
ascii chars. But for manpages with actual UTF8 characters (qemu
docs contains these), this change allows to see real characters
instead of mojibakes or substitutes.
Signed-off-By: Michael Tokarev <mjt at tls.msk.ru>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/Makefile b/Makefile
index 1bc3cb0..8d6b558 100644
--- a/Makefile
+++ b/Makefile
@@ -347,28 +347,29 @@ QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
+POD2MAN = pod2man --utf8
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
- pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
+ $(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
" GEN $@")
qemu-img.1: qemu-img.texi qemu-img-cmds.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
- pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
+ $(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \
" GEN $@")
fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \
- pod2man --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
+ $(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
" GEN $@")
qemu-nbd.8: qemu-nbd.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
- pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
+ $(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
" GEN $@")
dvi: qemu-doc.dvi qemu-tech.dvi
diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl
index 9ed056a..94097fb 100755
--- a/scripts/texi2pod.pl
+++ b/scripts/texi2pod.pl
@@ -36,6 +36,7 @@ $fnno = 1;
$inf = "";
$ibase = "";
@ipath = ();
+$encoding = undef;
while ($_ = shift) {
if (/^-D(.*)$/) {
@@ -97,6 +98,12 @@ while(<$inf>) {
/^\@setfilename\s+([^.]+)/ and $fn = $1, next;
/^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
+ # Look for document encoding
+ /^\@documentencoding\s+([^.]+)/ and do {
+ $encoding = $1 unless defined $encoding;
+ next;
+ };
+
# Identify a man title but keep only the one we are interested in.
/^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
if (exists $defs{$1}) {
@@ -336,6 +343,8 @@ $inf = pop @instack;
die "No filename or title\n" unless defined $fn && defined $tl;
+print "=encoding $encoding\n\n" if defined $encoding;
+
$sects{NAME} = "$fn \- $tl\n";
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
commit 813da6277cf6325ee97e7b7724e1672053356f4c
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Mar 19 12:25:11 2012 -0700
tcg: Use the GDB JIT debugging interface.
This allows us to generate unwind info for the dynamicly generated
code in the code_gen_buffer. Only i386 is converted at this point.
Signed-off-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/elf.h b/elf.h
index 2e05d34..310e05a 100644
--- a/elf.h
+++ b/elf.h
@@ -216,6 +216,7 @@ typedef int64_t Elf64_Sxword;
#define ELF_ST_BIND(x) ((x) >> 4)
#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
+#define ELF_ST_INFO(bind, type) (((bind) << 4) | ((type) & 0xf))
#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
diff --git a/exec.c b/exec.c
index 265e895..6731ab8 100644
--- a/exec.c
+++ b/exec.c
@@ -636,6 +636,7 @@ void tcg_exec_init(unsigned long tb_size)
cpu_gen_init();
code_gen_alloc(tb_size);
code_gen_ptr = code_gen_buffer;
+ tcg_register_jit(code_gen_buffer, code_gen_buffer_size);
page_init();
#if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
/* There's no guest base to take into account, so go ahead and
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 43a51a1..871a7e7 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -1989,22 +1989,29 @@ static int tcg_target_callee_save_regs[] = {
#endif
};
+/* Compute frame size via macros, to share between tcg_target_qemu_prologue
+ and tcg_register_jit. */
+
+#define PUSH_SIZE \
+ ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \
+ * (TCG_TARGET_REG_BITS / 8))
+
+#define FRAME_SIZE \
+ ((PUSH_SIZE \
+ + TCG_STATIC_CALL_ARGS_SIZE \
+ + CPU_TEMP_BUF_NLONGS * sizeof(long) \
+ + TCG_TARGET_STACK_ALIGN - 1) \
+ & ~(TCG_TARGET_STACK_ALIGN - 1))
+
/* Generate global QEMU prologue and epilogue code */
static void tcg_target_qemu_prologue(TCGContext *s)
{
- int i, frame_size, push_size, stack_addend;
+ int i, stack_addend;
/* TB prologue */
/* Reserve some stack space, also for TCG temps. */
- push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
- push_size *= TCG_TARGET_REG_BITS / 8;
-
- frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
- CPU_TEMP_BUF_NLONGS * sizeof(long);
- frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
- ~(TCG_TARGET_STACK_ALIGN - 1);
- stack_addend = frame_size - push_size;
+ stack_addend = FRAME_SIZE - PUSH_SIZE;
tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
CPU_TEMP_BUF_NLONGS * sizeof(long));
@@ -2070,3 +2077,92 @@ static void tcg_target_init(TCGContext *s)
tcg_add_target_add_op_defs(x86_op_defs);
}
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t id;
+ uint8_t version;
+ char augmentation[1];
+ uint8_t code_align;
+ uint8_t data_align;
+ uint8_t return_column;
+} DebugFrameCIE;
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t cie_offset;
+ tcg_target_long func_start __attribute__((packed));
+ tcg_target_long func_len __attribute__((packed));
+ uint8_t def_cfa[4];
+ uint8_t reg_ofs[14];
+} DebugFrameFDE;
+
+typedef struct {
+ DebugFrameCIE cie;
+ DebugFrameFDE fde;
+} DebugFrame;
+
+#if TCG_TARGET_REG_BITS == 64
+#define ELF_HOST_MACHINE EM_X86_64
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = 0x78, /* sleb128 -8 */
+ .cie.return_column = 16,
+
+ .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+ .fde.def_cfa = {
+ 12, 7, /* DW_CFA_def_cfa %rsp, ... */
+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
+ (FRAME_SIZE >> 7)
+ },
+ .fde.reg_ofs = {
+ 0x90, 1, /* DW_CFA_offset, %rip, -8 */
+ /* The following ordering must match tcg_target_callee_save_regs. */
+ 0x86, 2, /* DW_CFA_offset, %rbp, -16 */
+ 0x83, 3, /* DW_CFA_offset, %rbx, -24 */
+ 0x8c, 4, /* DW_CFA_offset, %r12, -32 */
+ 0x8d, 5, /* DW_CFA_offset, %r13, -40 */
+ 0x8e, 6, /* DW_CFA_offset, %r14, -48 */
+ 0x8f, 7, /* DW_CFA_offset, %r15, -56 */
+ }
+};
+#else
+#define ELF_HOST_MACHINE EM_386
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = 0x7c, /* sleb128 -4 */
+ .cie.return_column = 8,
+
+ .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+ .fde.def_cfa = {
+ 12, 4, /* DW_CFA_def_cfa %esp, ... */
+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
+ (FRAME_SIZE >> 7)
+ },
+ .fde.reg_ofs = {
+ 0x88, 1, /* DW_CFA_offset, %eip, -4 */
+ /* The following ordering must match tcg_target_callee_save_regs. */
+ 0x85, 2, /* DW_CFA_offset, %ebp, -8 */
+ 0x83, 3, /* DW_CFA_offset, %ebx, -12 */
+ 0x86, 4, /* DW_CFA_offset, %esi, -16 */
+ 0x87, 5, /* DW_CFA_offset, %edi, -20 */
+ }
+};
+#endif
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+ /* We're expecting a 2 byte uleb128 encoded value. */
+ assert(FRAME_SIZE >> 14 == 0);
+
+ debug_frame.fde.func_start = (tcg_target_long) buf;
+ debug_frame.fde.func_len = buf_size;
+
+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
diff --git a/tcg/tcg.c b/tcg/tcg.c
index ccfcd1a..eb595ce 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -28,6 +28,9 @@
#include "config.h"
+/* Define to jump the ELF file used to communicate with GDB. */
+#undef DEBUG_JIT
+
#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
/* define it to suppress various consistency checks (faster) */
#define NDEBUG
@@ -45,6 +48,18 @@
#include "cpu.h"
#include "tcg-op.h"
+
+#if TCG_TARGET_REG_BITS == 64
+# define ELF_CLASS ELFCLASS64
+#else
+# define ELF_CLASS ELFCLASS32
+#endif
+#ifdef HOST_WORDS_BIGENDIAN
+# define ELF_DATA ELFDATA2MSB
+#else
+# define ELF_DATA ELFDATA2LSB
+#endif
+
#include "elf.h"
#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
@@ -57,6 +72,10 @@ static void tcg_target_qemu_prologue(TCGContext *s);
static void patch_reloc(uint8_t *code_ptr, int type,
tcg_target_long value, tcg_target_long addend);
+static void tcg_register_jit_int(void *buf, size_t size,
+ void *debug_frame, size_t debug_frame_size)
+ __attribute__((unused));
+
/* Forward declarations for functions declared and used in tcg-target.c. */
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
@@ -2231,3 +2250,178 @@ void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
cpu_fprintf(f, "[TCG profiler not compiled]\n");
}
#endif
+
+#ifdef ELF_HOST_MACHINE
+/* The backend should define ELF_HOST_MACHINE to indicate both what value to
+ put into the ELF image and to indicate support for the feature. */
+
+/* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */
+typedef enum {
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry {
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const void *symfile_addr;
+ uint64_t symfile_size;
+};
+
+struct jit_descriptor {
+ uint32_t version;
+ uint32_t action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+};
+
+void __jit_debug_register_code(void) __attribute__((noinline));
+void __jit_debug_register_code(void)
+{
+ asm("");
+}
+
+/* Must statically initialize the version, because GDB may check
+ the version before we can set it. */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+/* End GDB interface. */
+
+static int find_string(const char *strtab, const char *str)
+{
+ const char *p = strtab + 1;
+
+ while (1) {
+ if (strcmp(p, str) == 0) {
+ return p - strtab;
+ }
+ p += strlen(p) + 1;
+ }
+}
+
+static void tcg_register_jit_int(void *buf, size_t buf_size,
+ void *debug_frame, size_t debug_frame_size)
+{
+ static const char strings[64] =
+ "\0"
+ ".text\0"
+ ".debug_frame\0"
+ ".symtab\0"
+ ".strtab\0"
+ "code_gen_buffer";
+
+ struct ElfImage {
+ ElfW(Ehdr) ehdr;
+ ElfW(Phdr) phdr;
+ ElfW(Shdr) shdr[5];
+ ElfW(Sym) sym[1];
+ char str[64];
+ };
+
+ /* We only need a single jit entry; statically allocate it. */
+ static struct jit_code_entry one_entry;
+
+ size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
+ struct ElfImage *img = g_malloc0(img_size);
+
+ img->ehdr.e_ident[EI_MAG0] = ELFMAG0;
+ img->ehdr.e_ident[EI_MAG1] = ELFMAG1;
+ img->ehdr.e_ident[EI_MAG2] = ELFMAG2;
+ img->ehdr.e_ident[EI_MAG3] = ELFMAG3;
+ img->ehdr.e_ident[EI_CLASS] = ELF_CLASS;
+ img->ehdr.e_ident[EI_DATA] = ELF_DATA;
+ img->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ img->ehdr.e_type = ET_EXEC;
+ img->ehdr.e_machine = ELF_HOST_MACHINE;
+ img->ehdr.e_version = EV_CURRENT;
+ img->ehdr.e_phoff = offsetof(struct ElfImage, phdr);
+ img->ehdr.e_shoff = offsetof(struct ElfImage, shdr);
+ img->ehdr.e_ehsize = sizeof(ElfW(Shdr));
+ img->ehdr.e_phentsize = sizeof(ElfW(Phdr));
+ img->ehdr.e_phnum = 1;
+ img->ehdr.e_shentsize = sizeof(img->shdr[0]);
+ img->ehdr.e_shnum = ARRAY_SIZE(img->shdr);
+ img->ehdr.e_shstrndx = ARRAY_SIZE(img->shdr) - 1;
+
+ img->phdr.p_type = PT_LOAD;
+ img->phdr.p_offset = (char *)buf - (char *)img;
+ img->phdr.p_vaddr = (ElfW(Addr))buf;
+ img->phdr.p_paddr = img->phdr.p_vaddr;
+ img->phdr.p_filesz = 0;
+ img->phdr.p_memsz = buf_size;
+ img->phdr.p_flags = PF_X;
+
+ memcpy(img->str, strings, sizeof(img->str));
+
+ img->shdr[0].sh_type = SHT_NULL;
+
+ /* Trick: The contents of code_gen_buffer are not present in this fake
+ ELF file; that got allocated elsewhere, discontiguously. Therefore
+ we mark .text as SHT_NOBITS (similar to .bss) so that readers will
+ not look for contents. We can record any address at will. */
+ img->shdr[1].sh_name = find_string(img->str, ".text");
+ img->shdr[1].sh_type = SHT_NOBITS;
+ img->shdr[1].sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ img->shdr[1].sh_addr = (ElfW(Addr))buf;
+ img->shdr[1].sh_size = buf_size;
+
+ img->shdr[2].sh_name = find_string(img->str, ".debug_frame");
+ img->shdr[2].sh_type = SHT_PROGBITS;
+ img->shdr[2].sh_offset = sizeof(*img);
+ img->shdr[2].sh_size = debug_frame_size;
+ memcpy(img + 1, debug_frame, debug_frame_size);
+
+ img->shdr[3].sh_name = find_string(img->str, ".symtab");
+ img->shdr[3].sh_type = SHT_SYMTAB;
+ img->shdr[3].sh_offset = offsetof(struct ElfImage, sym);
+ img->shdr[3].sh_size = sizeof(img->sym);
+ img->shdr[3].sh_info = ARRAY_SIZE(img->sym);
+ img->shdr[3].sh_link = img->ehdr.e_shstrndx;
+ img->shdr[3].sh_entsize = sizeof(ElfW(Sym));
+
+ img->shdr[4].sh_name = find_string(img->str, ".strtab");
+ img->shdr[4].sh_type = SHT_STRTAB;
+ img->shdr[4].sh_offset = offsetof(struct ElfImage, str);
+ img->shdr[4].sh_size = sizeof(img->str);
+
+ img->sym[0].st_name = find_string(img->str, "code_gen_buffer");
+ img->sym[0].st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
+ img->sym[0].st_shndx = 1;
+ img->sym[0].st_value = (ElfW(Addr))buf;
+ img->sym[0].st_size = buf_size;
+
+#ifdef DEBUG_JIT
+ /* Enable this block to be able to debug the ELF image file creation.
+ One can use readelf, objdump, or other inspection utilities. */
+ {
+ FILE *f = fopen("/tmp/qemu.jit", "w+b");
+ if (f) {
+ if (fwrite(img, img_size, 1, f) != buf_size) {
+ /* Avoid stupid unused return value warning for fwrite. */
+ }
+ fclose(f);
+ }
+ }
+#endif
+
+ one_entry.symfile_addr = img;
+ one_entry.symfile_size = img_size;
+
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+ __jit_debug_descriptor.relevant_entry = &one_entry;
+ __jit_debug_descriptor.first_entry = &one_entry;
+ __jit_debug_register_code();
+}
+#else
+/* No support for the feature. Provide the entry point expected by exec.c. */
+
+static void tcg_register_jit_int(void *buf, size_t size,
+ void *debug_frame, size_t debug_frame_size)
+{
+}
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+}
+#endif /* ELF_HOST_MACHINE */
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 5f6c647..a83bddd 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -586,3 +586,5 @@ extern uint8_t code_gen_prologue[];
# define tcg_qemu_tb_exec(env, tb_ptr) \
((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
#endif
+
+void tcg_register_jit(void *buf, size_t buf_size);
commit 08c4ea294f38fa90c7e91d7402091ff8332bc65e
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 1 08:34:40 2012 +0100
fix screendump
Commit 45efb16124efef51de5157afc31984b5a47700f9 optimized a bit too
much. We can skip the vga_invalidate_display() in case no console
switch happened because we don't need a full redraw then. We can *not*
skip vga_hw_update() though, because the screen content will be stale
then in case nobody else calls vga_hw_update().
Trigger: vga textmode with vnc display and no client connected.
Reported-by: Avi Kivity <avi at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Reviewed-by: Alon Levy <alevy at redhat.com>
Tested-by: Avi Kivity <avi at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/hw/blizzard.c b/hw/blizzard.c
index c7d844d..29074c4 100644
--- a/hw/blizzard.c
+++ b/hw/blizzard.c
@@ -937,9 +937,7 @@ static void blizzard_screen_dump(void *opaque, const char *filename,
{
BlizzardState *s = (BlizzardState *) opaque;
- if (cswitch) {
- blizzard_update_display(opaque);
- }
+ blizzard_update_display(opaque);
if (s && ds_get_data(s->state))
ppm_save(filename, s->state->surface);
}
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
index f172093..4a08e9d 100644
--- a/hw/omap_lcdc.c
+++ b/hw/omap_lcdc.c
@@ -267,9 +267,8 @@ static int ppm_save(const char *filename, uint8_t *data,
static void omap_screen_dump(void *opaque, const char *filename, bool cswitch)
{
struct omap_lcd_panel_s *omap_lcd = opaque;
- if (cswitch) {
- omap_update_display(opaque);
- }
+
+ omap_update_display(opaque);
if (omap_lcd && ds_get_data(omap_lcd->state))
ppm_save(filename, ds_get_data(omap_lcd->state),
omap_lcd->width, omap_lcd->height,
diff --git a/hw/vga.c b/hw/vga.c
index 6dc98f6..f80860c 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2415,7 +2415,7 @@ static void vga_screen_dump(void *opaque, const char *filename, bool cswitch)
if (cswitch) {
vga_invalidate_display(s);
- vga_hw_update();
}
+ vga_hw_update();
ppm_save(filename, s->ds->surface);
}
commit bc09845431888a0a6a680c0feeca7c6a18f8ec43
Author: Stefan Weil <sw at weilnetz.de>
Date: Sun Mar 18 23:16:04 2012 +0100
target-sparc: Add compiler attribute to some functions which don't return
helper_raise_exception does not return, nor does do_unaligned_access.
Cc: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 1025752..885ad45 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -699,8 +699,9 @@ uint64_t cpu_tick_get_count(CPUTimer *timer);
void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
trap_state* cpu_tsptr(CPUSPARCState* env);
#endif
-void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write,
- int is_user, void *retaddr);
+void QEMU_NORETURN do_unaligned_access(CPUSPARCState *env, target_ulong addr,
+ int is_write, int is_user,
+ void *retaddr);
#define TB_FLAG_FPU_ENABLED (1 << 4)
#define TB_FLAG_AM_ENABLED (1 << 5)
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index c4d6225..e3c7fdd 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -78,7 +78,7 @@ DEF_HELPER_1(fcmpeq_fcc1, void, env)
DEF_HELPER_1(fcmpeq_fcc2, void, env)
DEF_HELPER_1(fcmpeq_fcc3, void, env)
#endif
-DEF_HELPER_2(raise_exception, void, env, int)
+DEF_HELPER_2(raise_exception, noreturn, env, int)
#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
DEF_HELPER_3(faddd, f64, env, f64, f64)
commit 59821ae8025dbf61323343fc074513d30013c9c0
Author: Stefan Weil <sw at weilnetz.de>
Date: Sun Mar 18 23:16:03 2012 +0100
target-mips: Add compiler attribute to some functions which don't return
helper_raise_exception_err does not return, nor do helper_raise_exception
and do_unaligned_access.
Cc: Aurelien Jarno <aurelien at aurel32.net>
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 442f684..76fb451 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -1,7 +1,7 @@
#include "def-helper.h"
-DEF_HELPER_2(raise_exception_err, void, i32, int)
-DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_2(raise_exception_err, noreturn, i32, int)
+DEF_HELPER_1(raise_exception, noreturn, i32)
#ifdef TARGET_MIPS64
DEF_HELPER_3(ldl, tl, tl, tl, int)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 3a20731..ce01225 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -2292,7 +2292,8 @@ void helper_wait (void)
#if !defined(CONFIG_USER_ONLY)
-static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
+static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
+ int is_user, void *retaddr);
#define MMUSUFFIX _mmu
#define ALIGNED_ONLY
commit 1367ff497aa5200970e555bf4cce07467c3e3652
Author: Stefan Weil <sw at weilnetz.de>
Date: Sun Mar 18 23:16:02 2012 +0100
Add support for target helper functions which don't return
Most functions which handle exceptions don't return.
With a compiler attribute (added by QEMU_NORETURN),
gcc can optimize the code.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Reviewed-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/def-helper.h b/def-helper.h
index 0e70c31..b98ff69 100644
--- a/def-helper.h
+++ b/def-helper.h
@@ -39,6 +39,7 @@
#endif
#define dh_alias_ptr ptr
#define dh_alias_void void
+#define dh_alias_noreturn noreturn
#define dh_alias_env ptr
#define dh_alias(t) glue(dh_alias_, t)
@@ -52,36 +53,42 @@
#define dh_ctype_tl target_ulong
#define dh_ctype_ptr void *
#define dh_ctype_void void
+#define dh_ctype_noreturn void QEMU_NORETURN
#define dh_ctype_env CPUArchState *
#define dh_ctype(t) dh_ctype_##t
/* We can't use glue() here because it falls foul of C preprocessor
recursive expansion rules. */
#define dh_retvar_decl0_void void
+#define dh_retvar_decl0_noreturn void
#define dh_retvar_decl0_i32 TCGv_i32 retval
#define dh_retvar_decl0_i64 TCGv_i64 retval
#define dh_retvar_decl0_ptr TCGv_ptr retval
#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
#define dh_retvar_decl_void
+#define dh_retvar_decl_noreturn
#define dh_retvar_decl_i32 TCGv_i32 retval,
#define dh_retvar_decl_i64 TCGv_i64 retval,
#define dh_retvar_decl_ptr TCGv_ptr retval,
#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
#define dh_retvar_void TCG_CALL_DUMMY_ARG
+#define dh_retvar_noreturn TCG_CALL_DUMMY_ARG
#define dh_retvar_i32 GET_TCGV_i32(retval)
#define dh_retvar_i64 GET_TCGV_i64(retval)
#define dh_retvar_ptr GET_TCGV_ptr(retval)
#define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
#define dh_is_64bit_void 0
+#define dh_is_64bit_noreturn 0
#define dh_is_64bit_i32 0
#define dh_is_64bit_i64 1
#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64)
#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
#define dh_is_signed_void 0
+#define dh_is_signed_noreturn 0
#define dh_is_signed_i32 0
#define dh_is_signed_s32 1
#define dh_is_signed_i64 0
commit 4daa187d49a9d242d0bda1f35e190486112915f6
Author: Avi Kivity <avi at redhat.com>
Date: Sun Mar 18 16:48:44 2012 +0200
scripts: add gdb support script
Add a script that enhances gdb to be aware of QEMU data structures.
This patch adds a single gdb command, 'qemu mtree'. The command is
similar to the monitor's 'info mtree', except that it prints MemoryRegion
addresses, and except for working from a core dump as well as a live instance.
Signed-off-by: Avi Kivity <avi at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py
new file mode 100644
index 0000000..8a0f305
--- /dev/null
+++ b/scripts/qemu-gdb.py
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+
+# GDB debugging support
+#
+# Copyright 2012 Red Hat, Inc. and/or its affiliates
+#
+# Authors:
+# Avi Kivity <avi at redhat.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.
+
+
+import gdb
+
+def isnull(ptr):
+ return ptr == gdb.Value(0).cast(ptr.type)
+
+def int128(p):
+ return long(p['lo']) + (long(p['hi']) << 64)
+
+class QemuCommand(gdb.Command):
+ '''Prefix for QEMU debug support commands'''
+ def __init__(self):
+ gdb.Command.__init__(self, 'qemu', gdb.COMMAND_DATA,
+ gdb.COMPLETE_NONE, True)
+
+class MtreeCommand(gdb.Command):
+ '''Display the memory tree hierarchy'''
+ def __init__(self):
+ gdb.Command.__init__(self, 'qemu mtree', gdb.COMMAND_DATA,
+ gdb.COMPLETE_NONE)
+ self.queue = []
+ def invoke(self, arg, from_tty):
+ self.seen = set()
+ self.queue_root('address_space_memory')
+ self.queue_root('address_space_io')
+ self.process_queue()
+ def queue_root(self, varname):
+ ptr = gdb.parse_and_eval(varname)['root']
+ self.queue.append(ptr)
+ def process_queue(self):
+ while self.queue:
+ ptr = self.queue.pop(0)
+ if long(ptr) in self.seen:
+ continue
+ self.print_item(ptr)
+ def print_item(self, ptr, offset = gdb.Value(0), level = 0):
+ self.seen.add(long(ptr))
+ addr = ptr['addr']
+ addr += offset
+ size = int128(ptr['size'])
+ alias = ptr['alias']
+ klass = ''
+ if not isnull(alias):
+ klass = ' (alias)'
+ elif not isnull(ptr['ops']):
+ klass = ' (I/O)'
+ elif bool(ptr['ram']):
+ klass = ' (RAM)'
+ gdb.write('%s%016x-%016x %s%s (@ %s)\n'
+ % (' ' * level,
+ long(addr),
+ long(addr + (size - 1)),
+ ptr['name'].string(),
+ klass,
+ ptr,
+ ),
+ gdb.STDOUT)
+ if not isnull(alias):
+ gdb.write('%s alias: %s@%016x (@ %s)\n' %
+ (' ' * level,
+ alias['name'].string(),
+ ptr['alias_offset'],
+ alias,
+ ),
+ gdb.STDOUT)
+ self.queue.append(alias)
+ subregion = ptr['subregions']['tqh_first']
+ level += 1
+ while not isnull(subregion):
+ self.print_item(subregion, addr, level)
+ subregion = subregion['subregions_link']['tqe_next']
+
+QemuCommand()
+MtreeCommand()
commit d56de074698662b102a1901e3bae425f8e4945bf
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date: Fri Mar 23 11:37:25 2012 +0000
xen_disk: when using AIO flush after the operation is completed
If ioreq->postsync call bdrv_flush when the AIO operation is actually
completed.
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 0f265a4..9cb0253 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -330,6 +330,9 @@ static void qemu_aio_complete(void *opaque, int ret)
if (ioreq->aio_inflight > 0) {
return;
}
+ if (ioreq->postsync) {
+ bdrv_flush(ioreq->blkdev->bs);
+ }
ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
ioreq_unmap(ioreq);
@@ -376,9 +379,6 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
goto err;
}
- if (ioreq->postsync) {
- bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
- }
qemu_aio_complete(ioreq, 0);
return 0;
commit 820914103ca55c0eb7ecf6f458f18cb7989f439e
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date: Fri Mar 23 11:39:51 2012 +0000
xen_disk: open disk with BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 68fa36a..0f265a4 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -584,10 +584,10 @@ static int blk_init(struct XenDevice *xendev)
}
/* read-only ? */
+ qflags = BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO;
if (strcmp(blkdev->mode, "w") == 0) {
- qflags = BDRV_O_RDWR;
+ qflags |= BDRV_O_RDWR;
} else {
- qflags = 0;
info |= VDISK_READONLY;
}
commit a13ccc991a852cf12f2c05f537c40ce239ae464f
Author: Alon Levy <alevy at redhat.com>
Date: Wed Mar 21 18:17:18 2012 +0200
ui/spice-display: use uintptr_t when casting qxl physical addresses
The current intptr_t casts are a problem when the address's highest
bit is 1, and it is cast to a intptr_t and then to uint64_t, such
as at:
surface.mem = (intptr_t)ssd->buf;
This causes the sign bit to be extended which causes a wrong address to
be passed on to spice, which then complains when it gets the wrong
slot_id number, since the slot_id is taken from the higher bits.
The assertion happens early - during the first primary surface creation.
This fixes running "-vga qxl -spice" with 32 bit compiled
qemu-system-i386.
Signed-off-by: Alon Levy <alevy at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 6d7563f..cb8a7ad 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -168,7 +168,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
drawable->bbox = ssd->dirty;
drawable->clip.type = SPICE_CLIP_TYPE_NONE;
drawable->effect = QXL_EFFECT_OPAQUE;
- drawable->release_info.id = (intptr_t)update;
+ drawable->release_info.id = (uintptr_t)update;
drawable->type = QXL_DRAW_COPY;
drawable->surfaces_dest[0] = -1;
drawable->surfaces_dest[1] = -1;
@@ -179,7 +179,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+ time_space.tv_nsec / 1000 / 1000;
drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
- drawable->u.copy.src_bitmap = (intptr_t)image;
+ drawable->u.copy.src_bitmap = (uintptr_t)image;
drawable->u.copy.src_area.right = bw;
drawable->u.copy.src_area.bottom = bh;
@@ -189,7 +189,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
image->bitmap.stride = bw * 4;
image->descriptor.width = image->bitmap.x = bw;
image->descriptor.height = image->bitmap.y = bh;
- image->bitmap.data = (intptr_t)(update->bitmap);
+ image->bitmap.data = (uintptr_t)(update->bitmap);
image->bitmap.palette = 0;
image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
@@ -210,7 +210,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
}
cmd->type = QXL_CMD_DRAW;
- cmd->data = (intptr_t)drawable;
+ cmd->data = (uintptr_t)drawable;
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
return update;
@@ -254,7 +254,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
surface.mouse_mode = true;
surface.flags = 0;
surface.type = 0;
- surface.mem = (intptr_t)ssd->buf;
+ surface.mem = (uintptr_t)ssd->buf;
surface.group_id = MEMSLOT_GROUP_HOST;
qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
commit 34d14c6d8c7af0d2457cf5730fe5a65a878c509d
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Wed Mar 7 13:36:48 2012 +0000
ui/spice-display.c: Fix compilation warnings on 32 bit hosts
Fix compilation failures ("cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]") by using
uintptr_t instead.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 28d6d4a..6d7563f 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -80,8 +80,8 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
if (async != QXL_SYNC) {
spice_qxl_add_memslot_async(&ssd->qxl, memslot,
- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_MEMSLOT_ADD_ASYNC));
+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+ QXL_IO_MEMSLOT_ADD_ASYNC));
} else {
ssd->worker->add_memslot(ssd->worker, memslot);
}
@@ -100,8 +100,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async);
if (async != QXL_SYNC) {
spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface,
- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_CREATE_PRIMARY_ASYNC));
+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+ QXL_IO_CREATE_PRIMARY_ASYNC));
} else {
ssd->worker->create_primary_surface(ssd->worker, id, surface);
}
@@ -113,8 +113,8 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async);
if (async != QXL_SYNC) {
spice_qxl_destroy_primary_surface_async(&ssd->qxl, id,
- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_DESTROY_PRIMARY_ASYNC));
+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+ QXL_IO_DESTROY_PRIMARY_ASYNC));
} else {
ssd->worker->destroy_primary_surface(ssd->worker, id);
}
commit b9f9be88385e9ab51d4163bfd66f015f14f56286
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Mar 10 16:58:35 2012 +0000
memory: print aliased IO ranges in info mtree
Print also I/O ports behind bridges and other aliases.
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Avi Kivity <avi at redhat.com>
diff --git a/memory.c b/memory.c
index 22b0352..a3f5b59 100644
--- a/memory.c
+++ b/memory.c
@@ -1621,6 +1621,13 @@ void mtree_info(fprintf_function mon_printf, void *f)
mon_printf(f, "memory\n");
mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head);
+ if (address_space_io.root &&
+ !QTAILQ_EMPTY(&address_space_io.root->subregions)) {
+ mon_printf(f, "I/O\n");
+ mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
+ }
+
+ mon_printf(f, "aliases\n");
/* print aliased regions */
QTAILQ_FOREACH(ml, &ml_head, queue) {
if (!ml->printed) {
@@ -1632,11 +1639,4 @@ void mtree_info(fprintf_function mon_printf, void *f)
QTAILQ_FOREACH_SAFE(ml, &ml_head, queue, ml2) {
g_free(ml);
}
-
- if (address_space_io.root &&
- !QTAILQ_EMPTY(&address_space_io.root->subregions)) {
- QTAILQ_INIT(&ml_head);
- mon_printf(f, "I/O\n");
- mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
- }
}
commit 4200872b37ee59b5432d010becaabf84709798c5
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Mar 10 16:57:10 2012 +0000
ioport: use INT64_MAX for IO ranges
Expression UINT64_MAX + 1 will make the range bigger than
what can be represented with a 64 bit type. This would
trigger an assert in int128_get64() after the next patch.
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Avi Kivity <avi at redhat.com>
diff --git a/ioport.c b/ioport.c
index 78a3b89..6e4ca0d 100644
--- a/ioport.c
+++ b/ioport.c
@@ -385,7 +385,7 @@ static void portio_list_add_1(PortioList *piolist,
* rather than an offset relative to to start + off_low.
*/
memory_region_init_io(region, ops, piolist->opaque, piolist->name,
- UINT64_MAX);
+ INT64_MAX);
memory_region_init_alias(alias, piolist->name,
region, start + off_low, off_high - off_low);
memory_region_add_subregion(piolist->address_space,
commit ff71f2e8cacefae99179993204172bc65e4303df
Author: Jason Wang <jasowang at redhat.com>
Date: Mon Mar 5 11:09:08 2012 +0800
rtl8139: do the network/host communication only in normal operating mode
According the spec, the card works in network/host communication mode only when
both EEM1 and EEM0 are unset in 93C46 Command Register (normal op
mode). So this patch check these bits before trying to receive packets.
As some guest driver (such as linux, see cp_init_hw() in 8139cp.c)
allocate rx ring after the recevier were enabled, this would cause our
emulation codes tries to dma into guest memory when the rx descriptor
is not properly configured. This patch fixes this.
Signed-off-by: Jason Wang <jasowang at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index f3322ea..4d553a8 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -791,6 +791,9 @@ static int rtl8139_can_receive(VLANClientState *nc)
return 1;
if (!rtl8139_receiver_enabled(s))
return 1;
+ /* network/host communication happens only in normal mode */
+ if ((s->Cfg9346 & Chip9346_op_mask) != Cfg9346_Normal)
+ return 0;
if (rtl8139_cp_receiver_enabled(s)) {
/* ??? Flow control not implemented in c+ mode.
@@ -833,6 +836,12 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
return -1;
}
+ /* check whether we are in normal mode */
+ if ((s->Cfg9346 & Chip9346_op_mask) != Cfg9346_Normal) {
+ DPRINTF("not in normal op mode\n");
+ return -1;
+ }
+
/* XXX: check this */
if (s->RxConfig & AcceptAllPhys) {
/* promiscuous: receive all */
commit eb46c5eda7d8b38c1407dd55f67cf4a6aa3b7b23
Author: Jason Wang <jasowang at redhat.com>
Date: Mon Mar 5 11:08:59 2012 +0800
rtl8139: correctly check the opmode
According to the spec, only when opmode is "Config. Register Write
Enable" could driver write to CONFIG0,1,3,4 and bits 13,12,8 of BMCR.
Currently, we allow modifying to those registers also when 8139 is in
"Auto-load" mode and "93C46 (93C56) Programming" mode. This patch
fixes this.
Signed-off-by: Jason Wang <jasowang at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 5b608f5..f3322ea 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -332,8 +332,10 @@ enum CSCRBits {
};
enum Cfg9346Bits {
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
+ Cfg9346_Normal = 0x00,
+ Cfg9346_Autoload = 0x40,
+ Cfg9346_Programming = 0x80,
+ Cfg9346_ConfigWrite = 0xC0,
};
typedef enum {
@@ -1451,7 +1453,7 @@ static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
static int rtl8139_config_writable(RTL8139State *s)
{
- if (s->Cfg9346 & Cfg9346_Unlock)
+ if ((s->Cfg9346 & Chip9346_op_mask) == Cfg9346_ConfigWrite)
{
return 1;
}
commit 7fc8d918b9674c3e9233d6d25da2457345d414a0
Author: Jason Wang <jasowang at redhat.com>
Date: Mon Mar 5 11:08:50 2012 +0800
net: move compute_mcast_idx() to net.h
Reduce duplicated codes.
Signed-off-by: Jason Wang <jasowang at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/eepro100.c b/hw/eepro100.c
index e3ba719..02e6f7e 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -322,33 +322,8 @@ static const uint16_t eepro100_mdi_mask[] = {
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
-#define POLYNOMIAL 0x04c11db6
-
static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
-/* From FreeBSD */
-/* XXX: optimize */
-static unsigned compute_mcast_idx(const uint8_t * ep)
-{
- uint32_t crc;
- int carry, i, j;
- uint8_t b;
-
- crc = 0xffffffff;
- for (i = 0; i < 6; i++) {
- b = *ep++;
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
- crc <<= 1;
- b >>= 1;
- if (carry) {
- crc = ((crc ^ POLYNOMIAL) | carry);
- }
- }
- }
- return (crc & BITS(7, 2)) >> 2;
-}
-
/* Read a 16 bit control/status (CSR) register. */
static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
{
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 71452e1..d02e60c 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -150,30 +150,6 @@ static void ne2000_update_irq(NE2000State *s)
qemu_set_irq(s->irq, (isr != 0));
}
-#define POLYNOMIAL 0x04c11db6
-
-/* From FreeBSD */
-/* XXX: optimize */
-static int compute_mcast_idx(const uint8_t *ep)
-{
- uint32_t crc;
- int carry, i, j;
- uint8_t b;
-
- crc = 0xffffffff;
- for (i = 0; i < 6; i++) {
- b = *ep++;
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
- crc <<= 1;
- b >>= 1;
- if (carry)
- crc = ((crc ^ POLYNOMIAL) | carry);
- }
- }
- return (crc >> 26);
-}
-
static int ne2000_buffer_full(NE2000State *s)
{
int avail, index, boundary;
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index 4c76969..350f731 100644
--- a/hw/opencores_eth.c
+++ b/hw/opencores_eth.c
@@ -351,31 +351,6 @@ static int open_eth_can_receive(VLANClientState *nc)
(rx_desc(s)->len_flags & RXD_E);
}
-#define POLYNOMIAL 0x04c11db6
-
-/* From FreeBSD */
-/* XXX: optimize */
-static unsigned compute_mcast_idx(const uint8_t *ep)
-{
- uint32_t crc;
- int carry, i, j;
- uint8_t b;
-
- crc = 0xffffffff;
- for (i = 0; i < 6; i++) {
- b = *ep++;
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
- crc <<= 1;
- b >>= 1;
- if (carry) {
- crc = ((crc ^ POLYNOMIAL) | carry);
- }
- }
- }
- return crc >> 26;
-}
-
static ssize_t open_eth_receive(VLANClientState *nc,
const uint8_t *buf, size_t size)
{
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 1d5f78b..5b608f5 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -708,30 +708,6 @@ static void rtl8139_update_irq(RTL8139State *s)
qemu_set_irq(s->dev.irq[0], (isr != 0));
}
-#define POLYNOMIAL 0x04c11db6
-
-/* From FreeBSD */
-/* XXX: optimize */
-static int compute_mcast_idx(const uint8_t *ep)
-{
- uint32_t crc;
- int carry, i, j;
- uint8_t b;
-
- crc = 0xffffffff;
- for (i = 0; i < 6; i++) {
- b = *ep++;
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
- crc <<= 1;
- b >>= 1;
- if (carry)
- crc = ((crc ^ POLYNOMIAL) | carry);
- }
- }
- return (crc >> 26);
-}
-
static int rtl8139_RxWrap(RTL8139State *s)
{
/* wrapping enabled; assume 1.5k more buffer space if size < 65536 */
diff --git a/net.c b/net.c
index c34474f..1922d8a 100644
--- a/net.c
+++ b/net.c
@@ -1475,3 +1475,26 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg)
default_net = 0;
return 0;
}
+
+/* From FreeBSD */
+/* XXX: optimize */
+unsigned compute_mcast_idx(const uint8_t *ep)
+{
+ uint32_t crc;
+ int carry, i, j;
+ uint8_t b;
+
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ b = *ep++;
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+ crc <<= 1;
+ b >>= 1;
+ if (carry) {
+ crc = ((crc ^ POLYNOMIAL) | carry);
+ }
+ }
+ }
+ return crc >> 26;
+}
diff --git a/net.h b/net.h
index 75a8c15..64993b4 100644
--- a/net.h
+++ b/net.h
@@ -182,6 +182,9 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
int net_handle_fd_param(Monitor *mon, const char *param);
+#define POLYNOMIAL 0x04c11db6
+unsigned compute_mcast_idx(const uint8_t *ep);
+
#define vmstate_offset_macaddr(_state, _field) \
vmstate_offset_array(_state, _field.a, uint8_t, \
sizeof(typeof_field(_state, _field)))
commit afe0a595356192d5f79703cf6462fcc112df007c
Author: Jason Wang <jasowang at redhat.com>
Date: Mon Mar 5 11:08:42 2012 +0800
rtl8139: support byte read to TxStatus registers
Some drivers (such as win7) use byte read for TxStatus registers, so we need to
support this to let guest driver behave correctly.
For writing, only double-word access is allowed by spec.
Signed-off-by: Jason Wang <jasowang at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index ccbde27..1d5f78b 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -2495,11 +2495,30 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32
rtl8139_transmit(s);
}
-static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset)
+static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint8_t addr, int size)
{
- uint32_t ret = s->TxStatus[txRegOffset/4];
+ uint32_t reg = (addr - TxStatus0) / 4;
+ uint32_t offset = addr & 0x3;
+ uint32_t ret = 0;
+
+ if (addr & (size - 1)) {
+ DPRINTF("not implemented read for TxStatus addr=0x%x size=0x%x\n", addr,
+ size);
+ return ret;
+ }
- DPRINTF("TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret);
+ switch (size) {
+ case 1: /* fall through */
+ case 2: /* fall through */
+ case 4:
+ ret = (s->TxStatus[reg] >> offset * 8) & ((1 << (size * 8)) - 1);
+ DPRINTF("TxStatus[%d] read addr=0x%x size=0x%x val=0x%08x\n", reg, addr,
+ size, ret);
+ break;
+ default:
+ DPRINTF("unsupported size 0x%x of TxStatus reading\n", size);
+ break;
+ }
return ret;
}
@@ -2970,6 +2989,9 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
case MAR0 ... MAR0+7:
ret = s->mult[addr - MAR0];
break;
+ case TxStatus0 ... TxStatus0+4*4-1:
+ ret = rtl8139_TxStatus_read(s, addr, 1);
+ break;
case ChipCmd:
ret = rtl8139_ChipCmd_read(s);
break;
@@ -3033,6 +3055,9 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
switch (addr)
{
+ case TxAddr0 ... TxAddr0+4*4-1:
+ ret = rtl8139_TxStatus_read(s, addr, 2);
+ break;
case IntrMask:
ret = rtl8139_IntrMask_read(s);
break;
@@ -3123,7 +3148,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
break;
case TxStatus0 ... TxStatus0+4*4-1:
- ret = rtl8139_TxStatus_read(s, addr-TxStatus0);
+ ret = rtl8139_TxStatus_read(s, addr, 4);
break;
case TxAddr0 ... TxAddr0+4*4-1:
commit b44ce451df7840a0c5dea784673529994bbe1b32
Author: Jason Wang <jasowang at redhat.com>
Date: Mon Mar 5 11:08:33 2012 +0800
rtl8139: remove unused marco
Signed-off-by: Jason Wang <jasowang at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index be4bc6a..ccbde27 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -65,9 +65,6 @@
#define PCI_FREQUENCY 33000000L
-/* debug RTL8139 card C+ mode only */
-//#define DEBUG_RTL8139CP 1
-
#define SET_MASKED(input, mask, curr) \
( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
commit cde31a0e3dc0e4ac83e454d6096350cec584adf1
Author: Jason Wang <jasowang at redhat.com>
Date: Wed Mar 7 11:17:48 2012 +0800
rtl8139: limit transmission buffer size in c+ mode
The tx buffer would be re-allocated for tx descriptor with big size
and without LS bit set, this would make guest driver could easily let
qemu to allocate unlimited.
In linux host, a glib failure were easy to be triggered:
GLib-ERROR **: gmem.c:176: failed to allocate 18446744071562067968 bytes
This patch fix this by adding a limit. As the spec didn't tell the maximum size
of buffer allowed, stick it to current CP_TX_BUFFER_SIZE (65536).
Changes from V1:
Drop the while statement and s->cplus_txbuffer check.
Signed-off-by: Jason Wang <jasowang at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 05b8e1e..be4bc6a 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -2061,13 +2061,12 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
s->cplus_txbuffer_len);
}
- while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
+ if (s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
{
- s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = g_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
-
- DPRINTF("+++ C+ mode transmission buffer space changed to %d\n",
- s->cplus_txbuffer_len);
+ /* The spec didn't tell the maximum size, stick to CP_TX_BUFFER_SIZE */
+ txsize = s->cplus_txbuffer_len - s->cplus_txbuffer_offset;
+ DPRINTF("+++ C+ mode transmission buffer overrun, truncated descriptor"
+ "length to %d\n", txsize);
}
if (!s->cplus_txbuffer)
commit 453058d3e7111632b795c85f7d3bb36df25d5beb
Author: Anthony PERARD <anthony.perard at citrix.com>
Date: Fri Feb 17 17:08:37 2012 +0000
pci_regs: Add PCI_EXP_TYPE_PCIE_BRIDGE
Signed-off-by: Anthony PERARD <anthony.perard at citrix.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_regs.h b/hw/pci_regs.h
index 6b42515..56a404b 100644
--- a/hw/pci_regs.h
+++ b/hw/pci_regs.h
@@ -392,6 +392,7 @@
#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */
+#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */
#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */
#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */
#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */
commit ca384784af5f472f0b94c9205f8c500c1b5a43b6
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Fri Mar 16 00:43:25 2012 +0200
virtio-net: add DATA_VALID flag
Add DATA_VALID flag from the Linux header, to
keep us in sync with that.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/virtio-net.h b/hw/virtio-net.h
index 4468741..36aa463 100644
--- a/hw/virtio-net.h
+++ b/hw/virtio-net.h
@@ -79,6 +79,7 @@ struct virtio_net_config
struct virtio_net_hdr
{
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset
+#define VIRTIO_NET_HDR_F_DATA_VALID 2 // Csum is valid
uint8_t flags;
#define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame
#define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO)
commit cd7898f714773f7a317b122eaa45e701fd4f9849
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Mar 4 15:35:29 2012 +0200
pci_bridge: upper 32 bit are long registers
Use pci_set_long for accesses.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index eeee8a6..866f0b6 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -249,8 +249,8 @@ void pci_bridge_disable_base_limit(PCIDevice *dev)
PCI_PREF_RANGE_MASK & 0xffff);
pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
PCI_PREF_RANGE_MASK & 0xffff);
- pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
- pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
+ pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0);
+ pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0);
}
/* reset bridge specific configuration registers */
@@ -285,8 +285,8 @@ void pci_bridge_reset_reg(PCIDevice *dev)
PCI_PREF_RANGE_MASK & 0xffff);
pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
PCI_PREF_RANGE_MASK & 0xffff);
- pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
- pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
+ pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0);
+ pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0);
pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
}
commit 68917102740d9aa96c8f3ed4b95eab9917e8c61b
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Mar 4 11:36:35 2012 +0200
pci: fix bridge IO/BASE
commit 5caef97a16010f818ea8b950e2ee24ba876643ad introduced
a regression: we do not make IO base/limit upper 16
bit registers writeable, so we should report a 16 bit
IO range type, not a 32 bit one.
Note that PCI_PREF_RANGE_TYPE_32 is 0x0, but PCI_IO_RANGE_TYPE_32 is 0x1.
In particular, this broke sparc64.
Note: this just reverts to behaviour prior to the commit above.
Making PCI_IO_BASE_UPPER16 and PCI_IO_LIMIT_UPPER16
registers writeable should, and seems to, work just as well, but
as no system seems to actually be interested in 32 bit IO,
let's not make unnecessary changes.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index fee27fc..6d08cef 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -633,8 +633,8 @@ static void pci_init_mask_bridge(PCIDevice *d)
memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);
/* Supported memory and i/o types */
- d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_32;
- d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_32;
+ d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16;
+ d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16;
pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
PCI_PREF_RANGE_TYPE_64);
pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
commit 633442ff56909214576549d34f5be1f50a67c5a6
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Tue Feb 21 15:58:59 2012 +0200
pcie: drop functionality moved to core
Now that core sets memory type correctly,
remove this code from pcie port implementation.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pcie_port.c b/hw/pcie_port.c
index 8a36f5c..d6350e5 100644
--- a/hw/pcie_port.c
+++ b/hw/pcie_port.c
@@ -27,23 +27,13 @@ void pcie_port_init_reg(PCIDevice *d)
pci_set_word(d->config + PCI_STATUS, 0);
pci_set_word(d->config + PCI_SEC_STATUS, 0);
- /* Unlike conventional pci bridge, some bits are hardwared to 0. */
+ /* Unlike conventional pci bridge, some bits are hardwired to 0. */
pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_PARITY |
PCI_BRIDGE_CTL_ISA |
PCI_BRIDGE_CTL_VGA |
PCI_BRIDGE_CTL_SERR |
PCI_BRIDGE_CTL_BUS_RESET);
-
- /* 7.5.3.5 Prefetchable Memory Base Limit
- * The Prefetchable Memory Base and Prefetchable Memory Limit registers
- * must indicate that 64-bit addresses are supported, as defined in
- * PCI-to-PCI Bridge Architecture Specification, Revision 1.2.
- */
- pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
- PCI_PREF_RANGE_TYPE_64);
- pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
- PCI_PREF_RANGE_TYPE_64);
}
/**************************************************************************
commit 15ab7a75335108c76700bea67602017fe305350d
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Tue Feb 21 15:49:01 2012 +0200
pci: set memory type for memory behind the bridge
As we make upper bits in IO and prefetcheable memory
registers writeable, we should declare support
for 64 bit prefetcheable memory and 32 bit io
in the bridge.
This changes the default for apb, dec, but I'm guessing
they got the defaults wrong by accident.
Alternatively, we could let bridges declare lack of
64 bit support and make the upper bits read-only zero.
Reported-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index 3ca5f4c..fee27fc 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -663,8 +663,11 @@ static void pci_init_mask_bridge(PCIDevice *d)
pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_DISCARD_STATUS);
d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK;
+ d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK;
pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE,
PCI_PREF_RANGE_TYPE_MASK);
+ pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT,
+ PCI_PREF_RANGE_TYPE_MASK);
}
static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
commit 4eb812f7603f57dc63f6b74e3c464a60ed5bc91b
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Jul 3 16:00:09 2011 +0300
pci: add standard bridge device
This adds support for a standard pci to pci bridge,
enabling support for more than 32 PCI devices in the system.
Device hotplug is supported by means of SHPC controller.
For guests with an SHPC driver, this allows robust hotplug
and even hotplug of nested bridges, up to 31 devices
per bridge.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index 5b97871..25400e9 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -213,7 +213,7 @@ hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
hw-obj-y += usb/libhw.o
hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o
-hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
+hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o
hw-obj-$(CONFIG_PCI) += msix.o msi.o
hw-obj-$(CONFIG_PCI) += shpc.o
hw-obj-$(CONFIG_PCI) += slotid_cap.o
diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c
new file mode 100644
index 0000000..eccaa58
--- /dev/null
+++ b/hw/pci_bridge_dev.c
@@ -0,0 +1,174 @@
+/*
+ * Standard PCI Bridge Device
+ *
+ * Copyright (c) 2011 Red Hat Inc. Author: Michael S. Tsirkin <mst at redhat.com>
+ *
+ * http://www.pcisig.com/specifications/conventional/pci_to_pci_bridge_architecture/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_bridge.h"
+#include "pci_ids.h"
+#include "msi.h"
+#include "shpc.h"
+#include "slotid_cap.h"
+#include "memory.h"
+#include "pci_internals.h"
+
+#define REDHAT_PCI_VENDOR_ID 0x1b36
+#define PCI_BRIDGE_DEV_VENDOR_ID REDHAT_PCI_VENDOR_ID
+#define PCI_BRIDGE_DEV_DEVICE_ID 0x1
+
+struct PCIBridgeDev {
+ PCIBridge bridge;
+ MemoryRegion bar;
+ uint8_t chassis_nr;
+#define PCI_BRIDGE_DEV_F_MSI_REQ 0
+ uint32_t flags;
+};
+typedef struct PCIBridgeDev PCIBridgeDev;
+
+/* Mapping mandated by PCI-to-PCI Bridge architecture specification,
+ * revision 1.2 */
+/* Table 9-1: Interrupt Binding for Devices Behind a Bridge */
+static int pci_bridge_dev_map_irq_fn(PCIDevice *dev, int irq_num)
+{
+ return (irq_num + PCI_SLOT(dev->devfn)) % PCI_NUM_PINS;
+}
+
+static int pci_bridge_dev_initfn(PCIDevice *dev)
+{
+ PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
+ PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
+ int err;
+ pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn);
+ err = pci_bridge_initfn(dev);
+ if (err) {
+ goto bridge_error;
+ }
+ memory_region_init(&bridge_dev->bar, "shpc-bar", shpc_bar_size(dev));
+ err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
+ if (err) {
+ goto shpc_error;
+ }
+ err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0);
+ if (err) {
+ goto slotid_error;
+ }
+ if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) &&
+ msi_supported) {
+ err = msi_init(dev, 0, 1, true, true);
+ if (err < 0) {
+ goto msi_error;
+ }
+ }
+ /* TODO: spec recommends using 64 bit prefetcheable BAR.
+ * Check whether that works well. */
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
+ dev->config[PCI_INTERRUPT_PIN] = 0x1;
+ return 0;
+msi_error:
+ slotid_cap_cleanup(dev);
+slotid_error:
+ shpc_cleanup(dev, &bridge_dev->bar);
+shpc_error:
+ memory_region_destroy(&bridge_dev->bar);
+bridge_error:
+ return err;
+}
+
+static int pci_bridge_dev_exitfn(PCIDevice *dev)
+{
+ PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
+ PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
+ int ret;
+ if (msi_present(dev)) {
+ msi_uninit(dev);
+ }
+ slotid_cap_cleanup(dev);
+ shpc_cleanup(dev, &bridge_dev->bar);
+ memory_region_destroy(&bridge_dev->bar);
+ ret = pci_bridge_exitfn(dev);
+ assert(!ret);
+ return 0;
+}
+
+static void pci_bridge_dev_write_config(PCIDevice *d,
+ uint32_t address, uint32_t val, int len)
+{
+ pci_bridge_write_config(d, address, val, len);
+ if (msi_present(d)) {
+ msi_write_config(d, address, val, len);
+ }
+ shpc_cap_write_config(d, address, val, len);
+}
+
+static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
+{
+ PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+ pci_bridge_reset(qdev);
+ if (msi_present(dev)) {
+ msi_reset(dev);
+ }
+ shpc_reset(dev);
+}
+
+static Property pci_bridge_dev_properties[] = {
+ /* Note: 0 is not a legal chassis number. */
+ DEFINE_PROP_UINT8("chassis_nr", PCIBridgeDev, chassis_nr, 0),
+ DEFINE_PROP_BIT("msi", PCIBridgeDev, flags, PCI_BRIDGE_DEV_F_MSI_REQ, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription pci_bridge_dev_vmstate = {
+ .name = "pci_bridge",
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(bridge.dev, PCIBridgeDev),
+ SHPC_VMSTATE(bridge.dev.shpc, PCIBridgeDev),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ k->init = pci_bridge_dev_initfn;
+ k->exit = pci_bridge_dev_exitfn;
+ k->config_write = pci_bridge_dev_write_config;
+ k->vendor_id = PCI_BRIDGE_DEV_VENDOR_ID;
+ k->device_id = PCI_BRIDGE_DEV_DEVICE_ID;
+ k->class_id = PCI_CLASS_BRIDGE_PCI;
+ k->is_bridge = 1,
+ dc->desc = "Standard PCI Bridge";
+ dc->reset = qdev_pci_bridge_dev_reset;
+ dc->props = pci_bridge_dev_properties;
+ dc->vmsd = &pci_bridge_dev_vmstate;
+}
+
+static TypeInfo pci_bridge_dev_info = {
+ .name = "pci-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIBridgeDev),
+ .class_init = pci_bridge_dev_class_init,
+};
+
+static void pci_bridge_dev_register(void)
+{
+ type_register_static(&pci_bridge_dev_info);
+}
+
+type_init(pci_bridge_dev_register);
commit 762833b3b88b7b79af442439a8b138a04786ec3d
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Wed Feb 15 19:17:59 2012 +0200
slotid: add slot id capability
This capability makes it possible for the guest to
report a unique chassis identifier to the user.
The spec also recommends making chassis indentifier
persist in eeprom.
This isn't implemented.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index 1e8034c..5b97871 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -216,6 +216,7 @@ hw-obj-y += fw_cfg.o
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
hw-obj-$(CONFIG_PCI) += msix.o msi.o
hw-obj-$(CONFIG_PCI) += shpc.o
+hw-obj-$(CONFIG_PCI) += slotid_cap.o
hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
hw-obj-y += watchdog.o
diff --git a/hw/pci.h b/hw/pci.h
index dc4d9d1..8d0aa49 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -129,6 +129,8 @@ enum {
/* Standard hot plug controller. */
#define QEMU_PCI_SHPC_BITNR 5
QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR),
+#define QEMU_PCI_SLOTID_BITNR 6
+ QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_BITNR),
};
#define TYPE_PCI_DEVICE "pci-device"
diff --git a/hw/slotid_cap.c b/hw/slotid_cap.c
new file mode 100644
index 0000000..0106452
--- /dev/null
+++ b/hw/slotid_cap.c
@@ -0,0 +1,44 @@
+#include "slotid_cap.h"
+#include "pci.h"
+
+#define SLOTID_CAP_LENGTH 4
+#define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1)
+
+int slotid_cap_init(PCIDevice *d, int nslots,
+ uint8_t chassis,
+ unsigned offset)
+{
+ int cap;
+ if (!chassis) {
+ error_report("Bridge chassis not specified. Each bridge is required "
+ "to be assigned a unique chassis id > 0.");
+ return -EINVAL;
+ }
+ if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) {
+ /* TODO: error report? */
+ return -EINVAL;
+ }
+
+ cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH);
+ if (cap < 0) {
+ return cap;
+ }
+ /* We make each chassis unique, this way each bridge is First in Chassis */
+ d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC |
+ (nslots << SLOTID_NSLOTS_SHIFT);
+ d->cmask[cap + PCI_SID_ESR] = 0xff;
+ d->config[cap + PCI_SID_CHASSIS_NR] = chassis;
+ /* Note: Chassis number register is non-volatile,
+ so we don't reset it. */
+ /* TODO: store in eeprom? */
+ d->wmask[cap + PCI_SID_CHASSIS_NR] = 0xff;
+
+ d->cap_present |= QEMU_PCI_CAP_SLOTID;
+ return 0;
+}
+
+void slotid_cap_cleanup(PCIDevice *d)
+{
+ /* TODO: cleanup config space? */
+ d->cap_present &= ~QEMU_PCI_CAP_SLOTID;
+}
diff --git a/hw/slotid_cap.h b/hw/slotid_cap.h
new file mode 100644
index 0000000..70db047
--- /dev/null
+++ b/hw/slotid_cap.h
@@ -0,0 +1,11 @@
+#ifndef PCI_SLOTID_CAP_H
+#define PCI_SLOTID_CAP_H
+
+#include "qemu-common.h"
+
+int slotid_cap_init(PCIDevice *dev, int nslots,
+ uint8_t chassis,
+ unsigned offset);
+void slotid_cap_cleanup(PCIDevice *dev);
+
+#endif
commit 1dc324d20f7404fd6a416f16c2cb9a4ec50a4dd7
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Feb 12 14:12:21 2012 +0200
shpc: standard hot plug controller
This adds support for SHPC interface, as defined by PCI Standard
Hot-Plug Controller and Subsystem Specification, Rev 1.0
http://www.pcisig.com/specifications/conventional/pci_hot_plug/SHPC_10
Only SHPC intergrated with a PCI-to-PCI bridge is supported,
SHPC integrated with a host bridge would need more work.
All main SHPC features are supported:
- MRL sensor
- Attention button
- Attention indicator
- Power indicator
Wake on hotplug and serr generation are stubbed out but unused
as we don't have interfaces to generate these events ATM.
One issue that isn't completely resolved is that qemu currently
expects an "eject" interface, which SHPC does not provide: it merely
removes the power to device and it's up to the user to remove the device
from slot. This patch works around that by ejecting the device
when power is removed and power LED goes off.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/Makefile.objs b/Makefile.objs
index 226b01d..1e8034c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -215,6 +215,7 @@ hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
hw-obj-$(CONFIG_PCI) += msix.o msi.o
+hw-obj-$(CONFIG_PCI) += shpc.o
hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
hw-obj-y += watchdog.o
diff --git a/hw/pci.h b/hw/pci.h
index 704d3f3..dc4d9d1 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -126,6 +126,9 @@ enum {
/* command register SERR bit enabled */
#define QEMU_PCI_CAP_SERR_BITNR 4
QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
+ /* Standard hot plug controller. */
+#define QEMU_PCI_SHPC_BITNR 5
+ QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR),
};
#define TYPE_PCI_DEVICE "pci-device"
@@ -230,6 +233,9 @@ struct PCIDevice {
/* PCI Express */
PCIExpressDevice exp;
+ /* SHPC */
+ SHPCDevice *shpc;
+
/* Location of option rom */
char *romfile;
bool has_rom;
diff --git a/hw/shpc.c b/hw/shpc.c
new file mode 100644
index 0000000..a5baf24
--- /dev/null
+++ b/hw/shpc.c
@@ -0,0 +1,681 @@
+#include <strings.h>
+#include <stdint.h>
+#include "range.h"
+#include "range.h"
+#include "shpc.h"
+#include "pci.h"
+#include "pci_internals.h"
+#include "msi.h"
+
+/* TODO: model power only and disabled slot states. */
+/* TODO: handle SERR and wakeups */
+/* TODO: consider enabling 66MHz support */
+
+/* TODO: remove fully only on state DISABLED and LED off.
+ * track state to properly record this. */
+
+/* SHPC Working Register Set */
+#define SHPC_BASE_OFFSET 0x00 /* 4 bytes */
+#define SHPC_SLOTS_33 0x04 /* 4 bytes. Also encodes PCI-X slots. */
+#define SHPC_SLOTS_66 0x08 /* 4 bytes. */
+#define SHPC_NSLOTS 0x0C /* 1 byte */
+#define SHPC_FIRST_DEV 0x0D /* 1 byte */
+#define SHPC_PHYS_SLOT 0x0E /* 2 byte */
+#define SHPC_PHYS_NUM_MAX 0x7ff
+#define SHPC_PHYS_NUM_UP 0x2000
+#define SHPC_PHYS_MRL 0x4000
+#define SHPC_PHYS_BUTTON 0x8000
+#define SHPC_SEC_BUS 0x10 /* 2 bytes */
+#define SHPC_SEC_BUS_33 0x0
+#define SHPC_SEC_BUS_66 0x1 /* Unused */
+#define SHPC_SEC_BUS_MASK 0x7
+#define SHPC_MSI_CTL 0x12 /* 1 byte */
+#define SHPC_PROG_IFC 0x13 /* 1 byte */
+#define SHPC_PROG_IFC_1_0 0x1
+#define SHPC_CMD_CODE 0x14 /* 1 byte */
+#define SHPC_CMD_TRGT 0x15 /* 1 byte */
+#define SHPC_CMD_TRGT_MIN 0x1
+#define SHPC_CMD_TRGT_MAX 0x1f
+#define SHPC_CMD_STATUS 0x16 /* 2 bytes */
+#define SHPC_CMD_STATUS_BUSY 0x1
+#define SHPC_CMD_STATUS_MRL_OPEN 0x2
+#define SHPC_CMD_STATUS_INVALID_CMD 0x4
+#define SHPC_CMD_STATUS_INVALID_MODE 0x8
+#define SHPC_INT_LOCATOR 0x18 /* 4 bytes */
+#define SHPC_INT_COMMAND 0x1
+#define SHPC_SERR_LOCATOR 0x1C /* 4 bytes */
+#define SHPC_SERR_INT 0x20 /* 4 bytes */
+#define SHPC_INT_DIS 0x1
+#define SHPC_SERR_DIS 0x2
+#define SHPC_CMD_INT_DIS 0x4
+#define SHPC_ARB_SERR_DIS 0x8
+#define SHPC_CMD_DETECTED 0x10000
+#define SHPC_ARB_DETECTED 0x20000
+ /* 4 bytes * slot # (start from 0) */
+#define SHPC_SLOT_REG(s) (0x24 + (s) * 4)
+ /* 2 bytes */
+#define SHPC_SLOT_STATUS(s) (0x0 + SHPC_SLOT_REG(s))
+
+/* Same slot state masks are used for command and status registers */
+#define SHPC_SLOT_STATE_MASK 0x03
+#define SHPC_SLOT_STATE_SHIFT \
+ (ffs(SHPC_SLOT_STATE_MASK) - 1)
+
+#define SHPC_STATE_NO 0x0
+#define SHPC_STATE_PWRONLY 0x1
+#define SHPC_STATE_ENABLED 0x2
+#define SHPC_STATE_DISABLED 0x3
+
+#define SHPC_SLOT_PWR_LED_MASK 0xC
+#define SHPC_SLOT_PWR_LED_SHIFT \
+ (ffs(SHPC_SLOT_PWR_LED_MASK) - 1)
+#define SHPC_SLOT_ATTN_LED_MASK 0x30
+#define SHPC_SLOT_ATTN_LED_SHIFT \
+ (ffs(SHPC_SLOT_ATTN_LED_MASK) - 1)
+
+#define SHPC_LED_NO 0x0
+#define SHPC_LED_ON 0x1
+#define SHPC_LED_BLINK 0x2
+#define SHPC_LED_OFF 0x3
+
+#define SHPC_SLOT_STATUS_PWR_FAULT 0x40
+#define SHPC_SLOT_STATUS_BUTTON 0x80
+#define SHPC_SLOT_STATUS_MRL_OPEN 0x100
+#define SHPC_SLOT_STATUS_66 0x200
+#define SHPC_SLOT_STATUS_PRSNT_MASK 0xC00
+#define SHPC_SLOT_STATUS_PRSNT_EMPTY 0x3
+#define SHPC_SLOT_STATUS_PRSNT_25W 0x1
+#define SHPC_SLOT_STATUS_PRSNT_15W 0x2
+#define SHPC_SLOT_STATUS_PRSNT_7_5W 0x0
+
+#define SHPC_SLOT_STATUS_PRSNT_PCIX 0x3000
+
+
+ /* 1 byte */
+#define SHPC_SLOT_EVENT_LATCH(s) (0x2 + SHPC_SLOT_REG(s))
+ /* 1 byte */
+#define SHPC_SLOT_EVENT_SERR_INT_DIS(d, s) (0x3 + SHPC_SLOT_REG(s))
+#define SHPC_SLOT_EVENT_PRESENCE 0x01
+#define SHPC_SLOT_EVENT_ISOLATED_FAULT 0x02
+#define SHPC_SLOT_EVENT_BUTTON 0x04
+#define SHPC_SLOT_EVENT_MRL 0x08
+#define SHPC_SLOT_EVENT_CONNECTED_FAULT 0x10
+/* Bits below are used for Serr/Int disable only */
+#define SHPC_SLOT_EVENT_MRL_SERR_DIS 0x20
+#define SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS 0x40
+
+#define SHPC_MIN_SLOTS 1
+#define SHPC_MAX_SLOTS 31
+#define SHPC_SIZEOF(d) SHPC_SLOT_REG((d)->shpc->nslots)
+
+/* SHPC Slot identifiers */
+
+/* Hotplug supported at 31 slots out of the total 32. We reserve slot 0,
+ and give the rest of them physical *and* pci numbers starting from 1, so
+ they match logical numbers. Note: this means that multiple slots must have
+ different chassis number values, to make chassis+physical slot unique.
+ TODO: make this configurable? */
+#define SHPC_IDX_TO_LOGICAL(slot) ((slot) + 1)
+#define SHPC_LOGICAL_TO_IDX(target) ((target) - 1)
+#define SHPC_IDX_TO_PCI(slot) ((slot) + 1)
+#define SHPC_PCI_TO_IDX(pci_slot) ((pci_slot) - 1)
+#define SHPC_IDX_TO_PHYSICAL(slot) ((slot) + 1)
+
+static int roundup_pow_of_two(int x)
+{
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+ return x + 1;
+}
+
+static uint16_t shpc_get_status(SHPCDevice *shpc, int slot, uint16_t msk)
+{
+ uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
+ return (pci_get_word(status) & msk) >> (ffs(msk) - 1);
+}
+
+static void shpc_set_status(SHPCDevice *shpc,
+ int slot, uint8_t value, uint16_t msk)
+{
+ uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
+ pci_word_test_and_clear_mask(status, msk);
+ pci_word_test_and_set_mask(status, value << (ffs(msk) - 1));
+}
+
+static void shpc_interrupt_update(PCIDevice *d)
+{
+ SHPCDevice *shpc = d->shpc;
+ int slot;
+ int level = 0;
+ uint32_t serr_int;
+ uint32_t int_locator = 0;
+
+ /* Update interrupt locator register */
+ for (slot = 0; slot < shpc->nslots; ++slot) {
+ uint8_t event = shpc->config[SHPC_SLOT_EVENT_LATCH(slot)];
+ uint8_t disable = shpc->config[SHPC_SLOT_EVENT_SERR_INT_DIS(d, slot)];
+ uint32_t mask = 1 << SHPC_IDX_TO_LOGICAL(slot);
+ if (event & ~disable) {
+ int_locator |= mask;
+ }
+ }
+ serr_int = pci_get_long(shpc->config + SHPC_SERR_INT);
+ if ((serr_int & SHPC_CMD_DETECTED) && !(serr_int & SHPC_CMD_INT_DIS)) {
+ int_locator |= SHPC_INT_COMMAND;
+ }
+ pci_set_long(shpc->config + SHPC_INT_LOCATOR, int_locator);
+ level = (!(serr_int & SHPC_INT_DIS) && int_locator) ? 1 : 0;
+ if (msi_enabled(d) && shpc->msi_requested != level)
+ msi_notify(d, 0);
+ else
+ qemu_set_irq(d->irq[0], level);
+ shpc->msi_requested = level;
+}
+
+static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed)
+{
+ switch (speed) {
+ case SHPC_SEC_BUS_33:
+ shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK;
+ shpc->config[SHPC_SEC_BUS] |= speed;
+ break;
+ default:
+ pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
+ SHPC_CMD_STATUS_INVALID_MODE);
+ }
+}
+
+void shpc_reset(PCIDevice *d)
+{
+ SHPCDevice *shpc = d->shpc;
+ int nslots = shpc->nslots;
+ int i;
+ memset(shpc->config, 0, SHPC_SIZEOF(d));
+ pci_set_byte(shpc->config + SHPC_NSLOTS, nslots);
+ pci_set_long(shpc->config + SHPC_SLOTS_33, nslots);
+ pci_set_long(shpc->config + SHPC_SLOTS_66, 0);
+ pci_set_byte(shpc->config + SHPC_FIRST_DEV, SHPC_IDX_TO_PCI(0));
+ pci_set_word(shpc->config + SHPC_PHYS_SLOT,
+ SHPC_IDX_TO_PHYSICAL(0) |
+ SHPC_PHYS_NUM_UP |
+ SHPC_PHYS_MRL |
+ SHPC_PHYS_BUTTON);
+ pci_set_long(shpc->config + SHPC_SERR_INT, SHPC_INT_DIS |
+ SHPC_SERR_DIS |
+ SHPC_CMD_INT_DIS |
+ SHPC_ARB_SERR_DIS);
+ pci_set_byte(shpc->config + SHPC_PROG_IFC, SHPC_PROG_IFC_1_0);
+ pci_set_word(shpc->config + SHPC_SEC_BUS, SHPC_SEC_BUS_33);
+ for (i = 0; i < shpc->nslots; ++i) {
+ pci_set_byte(shpc->config + SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
+ SHPC_SLOT_EVENT_PRESENCE |
+ SHPC_SLOT_EVENT_ISOLATED_FAULT |
+ SHPC_SLOT_EVENT_BUTTON |
+ SHPC_SLOT_EVENT_MRL |
+ SHPC_SLOT_EVENT_CONNECTED_FAULT |
+ SHPC_SLOT_EVENT_MRL_SERR_DIS |
+ SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
+ if (shpc->sec_bus->devices[PCI_DEVFN(SHPC_IDX_TO_PCI(i), 0)]) {
+ shpc_set_status(shpc, i, SHPC_STATE_ENABLED, SHPC_SLOT_STATE_MASK);
+ shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_MRL_OPEN);
+ shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_7_5W,
+ SHPC_SLOT_STATUS_PRSNT_MASK);
+ shpc_set_status(shpc, i, SHPC_LED_ON, SHPC_SLOT_PWR_LED_MASK);
+ } else {
+ shpc_set_status(shpc, i, SHPC_STATE_DISABLED, SHPC_SLOT_STATE_MASK);
+ shpc_set_status(shpc, i, 1, SHPC_SLOT_STATUS_MRL_OPEN);
+ shpc_set_status(shpc, i, SHPC_SLOT_STATUS_PRSNT_EMPTY,
+ SHPC_SLOT_STATUS_PRSNT_MASK);
+ shpc_set_status(shpc, i, SHPC_LED_OFF, SHPC_SLOT_PWR_LED_MASK);
+ }
+ shpc_set_status(shpc, i, 0, SHPC_SLOT_STATUS_66);
+ }
+ shpc_set_sec_bus_speed(shpc, SHPC_SEC_BUS_33);
+ shpc->msi_requested = 0;
+ shpc_interrupt_update(d);
+}
+
+static void shpc_invalid_command(SHPCDevice *shpc)
+{
+ pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
+ SHPC_CMD_STATUS_INVALID_CMD);
+}
+
+static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
+{
+ int devfn;
+ int pci_slot = SHPC_IDX_TO_PCI(slot);
+ for (devfn = PCI_DEVFN(pci_slot, 0);
+ devfn <= PCI_DEVFN(pci_slot, PCI_FUNC_MAX - 1);
+ ++devfn) {
+ PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
+ if (affected_dev) {
+ qdev_free(&affected_dev->qdev);
+ }
+ }
+}
+
+static void shpc_slot_command(SHPCDevice *shpc, uint8_t target,
+ uint8_t state, uint8_t power, uint8_t attn)
+{
+ uint8_t current_state;
+ int slot = SHPC_LOGICAL_TO_IDX(target);
+ if (target < SHPC_CMD_TRGT_MIN || slot >= shpc->nslots) {
+ shpc_invalid_command(shpc);
+ return;
+ }
+ current_state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
+ if (current_state == SHPC_STATE_ENABLED && state == SHPC_STATE_PWRONLY) {
+ shpc_invalid_command(shpc);
+ return;
+ }
+
+ switch (power) {
+ case SHPC_LED_NO:
+ break;
+ default:
+ /* TODO: send event to monitor */
+ shpc_set_status(shpc, slot, power, SHPC_SLOT_PWR_LED_MASK);
+ }
+ switch (attn) {
+ case SHPC_LED_NO:
+ break;
+ default:
+ /* TODO: send event to monitor */
+ shpc_set_status(shpc, slot, attn, SHPC_SLOT_ATTN_LED_MASK);
+ }
+
+ if ((current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_PWRONLY) ||
+ (current_state == SHPC_STATE_DISABLED && state == SHPC_STATE_ENABLED)) {
+ shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
+ } else if ((current_state == SHPC_STATE_ENABLED ||
+ current_state == SHPC_STATE_PWRONLY) &&
+ state == SHPC_STATE_DISABLED) {
+ shpc_set_status(shpc, slot, state, SHPC_SLOT_STATE_MASK);
+ power = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
+ /* TODO: track what monitor requested. */
+ /* Look at LED to figure out whether it's ok to remove the device. */
+ if (power == SHPC_LED_OFF) {
+ shpc_free_devices_in_slot(shpc, slot);
+ shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
+ shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
+ SHPC_SLOT_STATUS_PRSNT_MASK);
+ shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
+ SHPC_SLOT_EVENT_BUTTON |
+ SHPC_SLOT_EVENT_MRL |
+ SHPC_SLOT_EVENT_PRESENCE;
+ }
+ }
+}
+
+static void shpc_command(SHPCDevice *shpc)
+{
+ uint8_t code = pci_get_byte(shpc->config + SHPC_CMD_CODE);
+ uint8_t speed;
+ uint8_t target;
+ uint8_t attn;
+ uint8_t power;
+ uint8_t state;
+ int i;
+
+ /* Clear status from the previous command. */
+ pci_word_test_and_clear_mask(shpc->config + SHPC_CMD_STATUS,
+ SHPC_CMD_STATUS_BUSY |
+ SHPC_CMD_STATUS_MRL_OPEN |
+ SHPC_CMD_STATUS_INVALID_CMD |
+ SHPC_CMD_STATUS_INVALID_MODE);
+ switch (code) {
+ case 0x00 ... 0x3f:
+ target = shpc->config[SHPC_CMD_TRGT] & SHPC_CMD_TRGT_MAX;
+ state = (code & SHPC_SLOT_STATE_MASK) >> SHPC_SLOT_STATE_SHIFT;
+ power = (code & SHPC_SLOT_PWR_LED_MASK) >> SHPC_SLOT_PWR_LED_SHIFT;
+ attn = (code & SHPC_SLOT_ATTN_LED_MASK) >> SHPC_SLOT_ATTN_LED_SHIFT;
+ shpc_slot_command(shpc, target, state, power, attn);
+ break;
+ case 0x40 ... 0x47:
+ speed = code & SHPC_SEC_BUS_MASK;
+ shpc_set_sec_bus_speed(shpc, speed);
+ break;
+ case 0x48:
+ /* Power only all slots */
+ /* first verify no slots are enabled */
+ for (i = 0; i < shpc->nslots; ++i) {
+ state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
+ if (state == SHPC_STATE_ENABLED) {
+ shpc_invalid_command(shpc);
+ goto done;
+ }
+ }
+ for (i = 0; i < shpc->nslots; ++i) {
+ if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
+ shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
+ SHPC_STATE_PWRONLY, SHPC_LED_ON, SHPC_LED_NO);
+ } else {
+ shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
+ SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
+ }
+ }
+ break;
+ case 0x49:
+ /* Enable all slots */
+ /* TODO: Spec says this shall fail if some are already enabled.
+ * This doesn't make sense - why not? a spec bug? */
+ for (i = 0; i < shpc->nslots; ++i) {
+ state = shpc_get_status(shpc, i, SHPC_SLOT_STATE_MASK);
+ if (state == SHPC_STATE_ENABLED) {
+ shpc_invalid_command(shpc);
+ goto done;
+ }
+ }
+ for (i = 0; i < shpc->nslots; ++i) {
+ if (!(shpc_get_status(shpc, i, SHPC_SLOT_STATUS_MRL_OPEN))) {
+ shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
+ SHPC_STATE_ENABLED, SHPC_LED_ON, SHPC_LED_NO);
+ } else {
+ shpc_slot_command(shpc, i + SHPC_CMD_TRGT_MIN,
+ SHPC_STATE_NO, SHPC_LED_OFF, SHPC_LED_NO);
+ }
+ }
+ break;
+ default:
+ shpc_invalid_command(shpc);
+ break;
+ }
+done:
+ pci_long_test_and_set_mask(shpc->config + SHPC_SERR_INT, SHPC_CMD_DETECTED);
+}
+
+static void shpc_write(PCIDevice *d, unsigned addr, uint64_t val, int l)
+{
+ SHPCDevice *shpc = d->shpc;
+ int i;
+ if (addr >= SHPC_SIZEOF(d)) {
+ return;
+ }
+ l = MIN(l, SHPC_SIZEOF(d) - addr);
+
+ /* TODO: code duplicated from pci.c */
+ for (i = 0; i < l; val >>= 8, ++i) {
+ unsigned a = addr + i;
+ uint8_t wmask = shpc->wmask[a];
+ uint8_t w1cmask = shpc->w1cmask[a];
+ assert(!(wmask & w1cmask));
+ shpc->config[a] = (shpc->config[a] & ~wmask) | (val & wmask);
+ shpc->config[a] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
+ }
+ if (ranges_overlap(addr, l, SHPC_CMD_CODE, 2)) {
+ shpc_command(shpc);
+ }
+ shpc_interrupt_update(d);
+}
+
+static uint64_t shpc_read(PCIDevice *d, unsigned addr, int l)
+{
+ uint64_t val = 0x0;
+ if (addr >= SHPC_SIZEOF(d)) {
+ return val;
+ }
+ l = MIN(l, SHPC_SIZEOF(d) - addr);
+ memcpy(&val, d->shpc->config + addr, l);
+ return val;
+}
+
+/* SHPC Bridge Capability */
+#define SHPC_CAP_LENGTH 0x08
+#define SHPC_CAP_DWORD_SELECT 0x2 /* 1 byte */
+#define SHPC_CAP_CxP 0x3 /* 1 byte: CSP, CIP */
+#define SHPC_CAP_DWORD_DATA 0x4 /* 4 bytes */
+#define SHPC_CAP_CSP_MASK 0x4
+#define SHPC_CAP_CIP_MASK 0x8
+
+static uint8_t shpc_cap_dword(PCIDevice *d)
+{
+ return pci_get_byte(d->config + d->shpc->cap + SHPC_CAP_DWORD_SELECT);
+}
+
+/* Update dword data capability register */
+static void shpc_cap_update_dword(PCIDevice *d)
+{
+ unsigned data;
+ data = shpc_read(d, shpc_cap_dword(d) * 4, 4);
+ pci_set_long(d->config + d->shpc->cap + SHPC_CAP_DWORD_DATA, data);
+}
+
+/* Add SHPC capability to the config space for the device. */
+static int shpc_cap_add_config(PCIDevice *d)
+{
+ uint8_t *config;
+ int config_offset;
+ config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC,
+ 0, SHPC_CAP_LENGTH);
+ if (config_offset < 0) {
+ return config_offset;
+ }
+ config = d->config + config_offset;
+
+ pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0);
+ pci_set_byte(config + SHPC_CAP_CxP, 0);
+ pci_set_long(config + SHPC_CAP_DWORD_DATA, 0);
+ d->shpc->cap = config_offset;
+ /* Make dword select and data writeable. */
+ pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
+ pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
+ return 0;
+}
+
+static uint64_t shpc_mmio_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ return shpc_read(opaque, addr, size);
+}
+
+static void shpc_mmio_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
+{
+ shpc_write(opaque, addr, val, size);
+}
+
+static const MemoryRegionOps shpc_mmio_ops = {
+ .read = shpc_mmio_read,
+ .write = shpc_mmio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ /* SHPC ECN requires dword accesses, but the original 1.0 spec doesn't.
+ * It's easier to suppport all sizes than worry about it. */
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev,
+ PCIHotplugState hotplug_state)
+{
+ int pci_slot = PCI_SLOT(affected_dev->devfn);
+ uint8_t state;
+ uint8_t led;
+ PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ SHPCDevice *shpc = d->shpc;
+ int slot = SHPC_PCI_TO_IDX(pci_slot);
+ if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) {
+ error_report("Unsupported PCI slot %d for standard hotplug "
+ "controller. Valid slots are between %d and %d.",
+ pci_slot, SHPC_IDX_TO_PCI(0),
+ SHPC_IDX_TO_PCI(shpc->nslots) - 1);
+ return -1;
+ }
+ /* Don't send event when device is enabled during qemu machine creation:
+ * it is present on boot, no hotplug event is necessary. We do send an
+ * event when the device is disabled later. */
+ if (hotplug_state == PCI_COLDPLUG_ENABLED) {
+ shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
+ shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
+ SHPC_SLOT_STATUS_PRSNT_MASK);
+ return 0;
+ }
+ if (hotplug_state == PCI_HOTPLUG_DISABLED) {
+ shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
+ state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
+ led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
+ if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
+ shpc_free_devices_in_slot(shpc, slot);
+ shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
+ shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
+ SHPC_SLOT_STATUS_PRSNT_MASK);
+ shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
+ SHPC_SLOT_EVENT_MRL |
+ SHPC_SLOT_EVENT_PRESENCE;
+ }
+ } else {
+ /* This could be a cancellation of the previous removal.
+ * We check MRL state to figure out. */
+ if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
+ shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
+ shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
+ SHPC_SLOT_STATUS_PRSNT_MASK);
+ shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
+ SHPC_SLOT_EVENT_BUTTON |
+ SHPC_SLOT_EVENT_MRL |
+ SHPC_SLOT_EVENT_PRESENCE;
+ } else {
+ /* Press attention button to cancel removal */
+ shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
+ SHPC_SLOT_EVENT_BUTTON;
+ }
+ }
+ shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
+ shpc_interrupt_update(d);
+ return 0;
+}
+
+/* Initialize the SHPC structure in bridge's BAR. */
+int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset)
+{
+ int i, ret;
+ int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */
+ SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc));
+ shpc->sec_bus = sec_bus;
+ ret = shpc_cap_add_config(d);
+ if (ret) {
+ g_free(d->shpc);
+ return ret;
+ }
+ if (nslots < SHPC_MIN_SLOTS) {
+ return 0;
+ }
+ if (nslots > SHPC_MAX_SLOTS ||
+ SHPC_IDX_TO_PCI(nslots) > PCI_SLOT_MAX) {
+ /* TODO: report an error mesage that makes sense. */
+ return -EINVAL;
+ }
+ shpc->nslots = nslots;
+ shpc->config = g_malloc0(SHPC_SIZEOF(d));
+ shpc->cmask = g_malloc0(SHPC_SIZEOF(d));
+ shpc->wmask = g_malloc0(SHPC_SIZEOF(d));
+ shpc->w1cmask = g_malloc0(SHPC_SIZEOF(d));
+
+ shpc_reset(d);
+
+ pci_set_long(shpc->config + SHPC_BASE_OFFSET, offset);
+
+ pci_set_byte(shpc->wmask + SHPC_CMD_CODE, 0xff);
+ pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
+ pci_set_byte(shpc->wmask + SHPC_CMD_TRGT, SHPC_CMD_TRGT_MAX);
+ pci_set_long(shpc->wmask + SHPC_SERR_INT,
+ SHPC_INT_DIS |
+ SHPC_SERR_DIS |
+ SHPC_CMD_INT_DIS |
+ SHPC_ARB_SERR_DIS);
+ pci_set_long(shpc->w1cmask + SHPC_SERR_INT,
+ SHPC_CMD_DETECTED |
+ SHPC_ARB_DETECTED);
+ for (i = 0; i < nslots; ++i) {
+ pci_set_byte(shpc->wmask +
+ SHPC_SLOT_EVENT_SERR_INT_DIS(d, i),
+ SHPC_SLOT_EVENT_PRESENCE |
+ SHPC_SLOT_EVENT_ISOLATED_FAULT |
+ SHPC_SLOT_EVENT_BUTTON |
+ SHPC_SLOT_EVENT_MRL |
+ SHPC_SLOT_EVENT_CONNECTED_FAULT |
+ SHPC_SLOT_EVENT_MRL_SERR_DIS |
+ SHPC_SLOT_EVENT_CONNECTED_FAULT_SERR_DIS);
+ pci_set_byte(shpc->w1cmask +
+ SHPC_SLOT_EVENT_LATCH(i),
+ SHPC_SLOT_EVENT_PRESENCE |
+ SHPC_SLOT_EVENT_ISOLATED_FAULT |
+ SHPC_SLOT_EVENT_BUTTON |
+ SHPC_SLOT_EVENT_MRL |
+ SHPC_SLOT_EVENT_CONNECTED_FAULT);
+ }
+
+ /* TODO: init cmask */
+ memory_region_init_io(&shpc->mmio, &shpc_mmio_ops, d, "shpc-mmio",
+ SHPC_SIZEOF(d));
+ shpc_cap_update_dword(d);
+ memory_region_add_subregion(bar, offset, &shpc->mmio);
+ pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev);
+
+ d->cap_present |= QEMU_PCI_CAP_SHPC;
+ return 0;
+}
+
+int shpc_bar_size(PCIDevice *d)
+{
+ return roundup_pow_of_two(SHPC_SLOT_REG(SHPC_MAX_SLOTS));
+}
+
+void shpc_cleanup(PCIDevice *d, MemoryRegion *bar)
+{
+ SHPCDevice *shpc = d->shpc;
+ d->cap_present &= ~QEMU_PCI_CAP_SHPC;
+ memory_region_del_subregion(bar, &shpc->mmio);
+ /* TODO: cleanup config space changes? */
+ g_free(shpc->config);
+ g_free(shpc->cmask);
+ g_free(shpc->wmask);
+ g_free(shpc->w1cmask);
+ memory_region_destroy(&shpc->mmio);
+ g_free(shpc);
+}
+
+void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
+{
+ if (!ranges_overlap(addr, l, d->shpc->cap, SHPC_CAP_LENGTH)) {
+ return;
+ }
+ if (ranges_overlap(addr, l, d->shpc->cap + SHPC_CAP_DWORD_DATA, 4)) {
+ unsigned dword_data;
+ dword_data = pci_get_long(d->shpc->config + d->shpc->cap
+ + SHPC_CAP_DWORD_DATA);
+ shpc_write(d, shpc_cap_dword(d) * 4, dword_data, 4);
+ }
+ /* Update cap dword data in case guest is going to read it. */
+ shpc_cap_update_dword(d);
+}
+
+static void shpc_save(QEMUFile *f, void *pv, size_t size)
+{
+ PCIDevice *d = container_of(pv, PCIDevice, shpc);
+ qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
+}
+
+static int shpc_load(QEMUFile *f, void *pv, size_t size)
+{
+ PCIDevice *d = container_of(pv, PCIDevice, shpc);
+ int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d));
+ if (ret != SHPC_SIZEOF(d)) {
+ return -EINVAL;
+ }
+ /* Make sure we don't lose notifications. An extra interrupt is harmless. */
+ d->shpc->msi_requested = 0;
+ shpc_interrupt_update(d);
+ return 0;
+}
+
+VMStateInfo shpc_vmstate_info = {
+ .name = "shpc",
+ .get = shpc_load,
+ .put = shpc_save,
+};
diff --git a/hw/shpc.h b/hw/shpc.h
new file mode 100644
index 0000000..130b71d
--- /dev/null
+++ b/hw/shpc.h
@@ -0,0 +1,48 @@
+#ifndef SHPC_H
+#define SHPC_H
+
+#include "qemu-common.h"
+#include "memory.h"
+#include "vmstate.h"
+
+struct SHPCDevice {
+ /* Capability offset in device's config space */
+ int cap;
+
+ /* # of hot-pluggable slots */
+ int nslots;
+
+ /* SHPC WRS: working register set */
+ uint8_t *config;
+
+ /* Used to enable checks on load. Note that writable bits are
+ * never checked even if set in cmask. */
+ uint8_t *cmask;
+
+ /* Used to implement R/W bytes */
+ uint8_t *wmask;
+
+ /* Used to implement RW1C(Write 1 to Clear) bytes */
+ uint8_t *w1cmask;
+
+ /* MMIO for the SHPC BAR */
+ MemoryRegion mmio;
+
+ /* Bus controlled by this SHPC */
+ PCIBus *sec_bus;
+
+ /* MSI already requested for this event */
+ int msi_requested;
+};
+
+void shpc_reset(PCIDevice *d);
+int shpc_bar_size(PCIDevice *dev);
+int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off);
+void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar);
+void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
+
+extern VMStateInfo shpc_vmstate_info;
+#define SHPC_VMSTATE(_field, _type) \
+ VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0)
+
+#endif
diff --git a/qemu-common.h b/qemu-common.h
index b0fdf5c..320f469 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -260,6 +260,7 @@ typedef struct SSIBus SSIBus;
typedef struct EventNotifier EventNotifier;
typedef struct VirtIODevice VirtIODevice;
typedef struct QEMUSGList QEMUSGList;
+typedef struct SHPCDevice SHPCDevice;
typedef uint64_t pcibus_t;
commit 8a3d80faf7794820da5e9666e4adf6a7d4f80f7b
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Mon Feb 20 01:34:01 2012 +0200
pci_bridge: user-friendly default bus name
For a pci bridge device, if we don't override
the name with custom code, the bus will be addressed as
<id>.0, where id is the id specified by the user.
Since PCI Bridge devices have a single bus each, we don't need
the index: address the bus using the parent device name.
This is better since this way users don't care about
our internal bus/device distinctions.
As far as I could see, we only have built-in
bridges at this point which always override the
name. So this change will only affect ioh3420.c.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index fea3873..eeee8a6 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -314,6 +314,16 @@ int pci_bridge_initfn(PCIDevice *dev)
pci_set_word(dev->config + PCI_SEC_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+ /*
+ * If we don't specify the name, the bus will be addressed as <id>.0, where
+ * id is the device id.
+ * Since PCI Bridge devices have a single bus each, we don't need the index:
+ * let users address the bus using the device name.
+ */
+ if (!br->bus_name && dev->qdev.id && *dev->qdev.id) {
+ br->bus_name = dev->qdev.id;
+ }
+
qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev,
br->bus_name);
sec_bus->parent_dev = dev;
commit d662210a440bf90bf0f5fb5eb8abd6244478c97d
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Feb 19 18:16:02 2012 +0200
pci: make another unused extern function static
Make pci_find_bus static and rename to pci_find_bus_nr to match
functionality.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index 691322d..3ca5f4c 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -63,6 +63,7 @@ struct BusInfo pci_bus_info = {
}
};
+static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
static void pci_update_mappings(PCIDevice *d);
static void pci_set_irq(void *opaque, int irq_num, int level);
static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom);
@@ -558,7 +559,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
if (!devaddr) {
*devfnp = -1;
- return pci_find_bus(pci_find_root_bus(0), 0);
+ return pci_find_bus_nr(pci_find_root_bus(0), 0);
}
if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
@@ -566,7 +567,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
}
*devfnp = PCI_DEVFN(slot, 0);
- return pci_find_bus(pci_find_root_bus(dom), bus);
+ return pci_find_bus_nr(pci_find_root_bus(dom), bus);
}
static void pci_init_cmask(PCIDevice *dev)
@@ -1140,7 +1141,7 @@ static void pci_for_each_device_under_bus(PCIBus *bus,
void pci_for_each_device(PCIBus *bus, int bus_num,
void (*fn)(PCIBus *b, PCIDevice *d))
{
- bus = pci_find_bus(bus, bus_num);
+ bus = pci_find_bus_nr(bus, bus_num);
if (bus) {
pci_for_each_device_under_bus(bus, fn);
@@ -1227,7 +1228,7 @@ static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
if (dev->config[PCI_SECONDARY_BUS] != 0) {
- PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
+ PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]);
if (child_bus) {
info->has_devices = true;
info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
@@ -1306,7 +1307,7 @@ static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
{
PciInfo *info = NULL;
- bus = pci_find_bus(bus, bus_num);
+ bus = pci_find_bus_nr(bus, bus_num);
if (bus) {
info = g_malloc0(sizeof(*info));
info->bus = bus_num;
@@ -1416,7 +1417,7 @@ static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
bus_num <= dev->config[PCI_SUBORDINATE_BUS];
}
-PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
+static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
{
PCIBus *sec;
@@ -1452,7 +1453,7 @@ PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
{
- bus = pci_find_bus(bus, bus_num);
+ bus = pci_find_bus_nr(bus, bus_num);
if (!bus)
return NULL;
diff --git a/hw/pci.h b/hw/pci.h
index 403aadb..704d3f3 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -299,7 +299,6 @@ int pci_bus_num(PCIBus *s);
void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDevice *d));
PCIBus *pci_find_root_bus(int domain);
int pci_find_domain(const PCIBus *bus);
-PCIBus *pci_find_bus(PCIBus *bus, int bus_num);
PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
int pci_qdev_find_device(const char *id, PCIDevice **pdev);
PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
commit 94a09e2c846374a96719cda2b4e1312d8c4b08a7
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Wed Feb 15 23:32:00 2012 +0200
pci: don't export an internal function
Make an internal function, pci_parse_devaddr,
static.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index 38e1de5..691322d 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -478,7 +478,7 @@ static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
* Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
* [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
*/
-int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
unsigned int *slotp, unsigned int *funcp)
{
const char *p;
diff --git a/hw/pci.h b/hw/pci.h
index 4f19fdb..403aadb 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -304,8 +304,6 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
int pci_qdev_find_device(const char *id, PCIDevice **pdev);
PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
-int pci_parse_devaddr(const char *addr, int *domp, int *busp,
- unsigned int *slotp, unsigned int *funcp);
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp);
commit 15a7a7780675eb99c093e29deefc5d6cc371bd87
Author: Anthony PERARD <anthony.perard at citrix.com>
Date: Fri Feb 17 17:08:36 2012 +0000
pci_regs: Fix value of PCI_EXP_TYPE_RC_EC.
Value check in PCI Express Base Specification rev 1.1
Signed-off-by: Anthony PERARD <anthony.perard at citrix.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci_regs.h b/hw/pci_regs.h
index e8357c3..6b42515 100644
--- a/hw/pci_regs.h
+++ b/hw/pci_regs.h
@@ -393,7 +393,7 @@
#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */
#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */
-#define PCI_EXP_TYPE_RC_EC 0x10 /* Root Complex Event Collector */
+#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */
#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */
#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */
#define PCI_EXP_DEVCAP 4 /* Device capabilities */
commit fdba487859bff44db21dc119ee2b1b3691c69f0f
Author: Anthony PERARD <anthony.perard at citrix.com>
Date: Mon Feb 13 12:20:13 2012 +0000
pci: Do not check if a bus exist in pci_parse_devaddr.
Actually, pci_parse_devaddr checks if the dom/bus of the PCI address exist. But
this should be the jobs of a caller. In fact, the two callers of this function
will try to retrieve the PCIBus related to the devaddr and return an error if
they cannot.
Signed-off-by: Anthony PERARD <anthony.perard at citrix.com>
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
diff --git a/hw/pci.c b/hw/pci.c
index bf046bf..38e1de5 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -529,10 +529,6 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
if (*e)
return -1;
- /* Note: QEMU doesn't implement domains other than 0 */
- if (!pci_find_bus(pci_find_root_bus(dom), bus))
- return -1;
-
*domp = dom;
*busp = bus;
*slotp = slot;
commit 95be1196030c003a65052fc7b8a3394fdac690a8
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Sun Feb 12 21:02:01 2012 +0200
pci_bridge: fix status: do not override cap bit
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 1ed4339..fea3873 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -305,8 +305,8 @@ int pci_bridge_initfn(PCIDevice *dev)
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
PCIBus *sec_bus = &br->sec_bus;
- pci_set_word(dev->config + PCI_STATUS,
- PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+ pci_word_test_and_set_mask(dev->config + PCI_STATUS,
+ PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
dev->config[PCI_HEADER_TYPE] =
(dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
More information about the Spice-commits
mailing list