]> git.proxmox.com Git - mirror_qemu.git/commitdiff
Merge remote branch 'origin/master' into pci
authorMichael S. Tsirkin <mst@redhat.com>
Thu, 5 May 2011 13:39:47 +0000 (16:39 +0300)
committerMichael S. Tsirkin <mst@redhat.com>
Thu, 5 May 2011 13:39:47 +0000 (16:39 +0300)
Conflicts:
exec.c

404 files changed:
.gitignore
.gitmodules
MAINTAINERS
Makefile
Makefile.objs
Makefile.target
acl.c
arch_init.h
arm-semi.c
audio/sdlaudio.c
balloon.c
block-migration.c
block.c
block.h
block/nbd.c
block/qed-check.c
block/qed-cluster.c
block/qed.c
block/qed.h
block/sheepdog.c
block/vdi.c
block/vpc.c
blockdev.c
bt-host.c
bt-vhci.c
buffered_file.c
configure
cpu-all.h
cpu-common.h
cpu-exec.c
cpus.c
cpus.h
darwin-user/commpage.c
default-configs/lm32-softmmu.mak
default-configs/unicore32-linux-user.mak [new file with mode: 0644]
device_tree.c
device_tree.h
disas.c
docs/ccid.txt [new file with mode: 0644]
docs/libcacard.txt [new file with mode: 0644]
docs/specs/qed_spec.txt
docs/tracing.txt
elf.h
exec-all.h
exec.c
fpu/softfloat-macros.h
fpu/softfloat-native.c
fpu/softfloat-native.h
fpu/softfloat-specialize.h
fpu/softfloat.c
fpu/softfloat.h
fsdev/file-op-9p.h [new file with mode: 0644]
fsdev/qemu-fsdev.h
gdbstub.c
gen-icount.h
hw/9pfs/virtio-9p-debug.c [new file with mode: 0644]
hw/9pfs/virtio-9p-debug.h [new file with mode: 0644]
hw/9pfs/virtio-9p-local.c [new file with mode: 0644]
hw/9pfs/virtio-9p-posix-acl.c [new file with mode: 0644]
hw/9pfs/virtio-9p-xattr-user.c [new file with mode: 0644]
hw/9pfs/virtio-9p-xattr.c [new file with mode: 0644]
hw/9pfs/virtio-9p-xattr.h [new file with mode: 0644]
hw/9pfs/virtio-9p.c [new file with mode: 0644]
hw/9pfs/virtio-9p.h [new file with mode: 0644]
hw/acpi.c
hw/acpi.h
hw/acpi_piix4.c
hw/adb.c
hw/ads7846.c
hw/an5206.c
hw/arm_boot.c
hw/arm_timer.c
hw/armv7m.c
hw/armv7m_nvic.c
hw/axis_dev88.c
hw/blizzard.c
hw/bt-hci-csr.c
hw/ccid-card-emulated.c [new file with mode: 0644]
hw/ccid-card-passthru.c [new file with mode: 0644]
hw/ccid.h [new file with mode: 0644]
hw/collie.c [new file with mode: 0644]
hw/cris-boot.c
hw/cuda.c
hw/dummy_m68k.c
hw/e1000.c
hw/eepro100.c
hw/empty_slot.c
hw/etraxfs.c
hw/fdc.c
hw/file-op-9p.h [deleted file]
hw/flash.h
hw/grlib_apbuart.c
hw/grlib_gptimer.c
hw/grlib_irqmp.c
hw/gumstix.c
hw/heathrow_pic.c
hw/hw.h
hw/ide.h
hw/ide/atapi.c [new file with mode: 0644]
hw/ide/core.c
hw/ide/ich.c
hw/ide/internal.h
hw/ide/isa.c
hw/ide/macio.c
hw/ide/microdrive.c
hw/ide/mmio.c
hw/ide/pci.c
hw/integratorcp.c
hw/ioapic.c
hw/isa-bus.c
hw/kvmclock.c
hw/lan9118.c
hw/lm32_boards.c
hw/lsi53c895a.c
hw/m48t59.c
hw/mac_dbdma.c
hw/mac_nvram.c
hw/mainstone.c
hw/max111x.c
hw/milkymist-ac97.c [new file with mode: 0644]
hw/milkymist-hpdmc.c [new file with mode: 0644]
hw/milkymist-hw.h [new file with mode: 0644]
hw/milkymist-memcard.c [new file with mode: 0644]
hw/milkymist-minimac2.c [new file with mode: 0644]
hw/milkymist-pfpu.c [new file with mode: 0644]
hw/milkymist-softusb.c [new file with mode: 0644]
hw/milkymist-sysctl.c [new file with mode: 0644]
hw/milkymist-tmu2.c [new file with mode: 0644]
hw/milkymist-uart.c [new file with mode: 0644]
hw/milkymist-vgafb.c [new file with mode: 0644]
hw/milkymist-vgafb_template.h [new file with mode: 0644]
hw/milkymist.c [new file with mode: 0644]
hw/mips_fulong2e.c
hw/mips_malta.c
hw/mips_r4k.c
hw/mipsnet.c
hw/multiboot.c
hw/musicpal.c
hw/nand.c
hw/ne2000.c
hw/omap_sx1.c
hw/pc_piix.c
hw/pcie.c
hw/pcnet-pci.c
hw/pcnet.c
hw/pflash_cfi02.c
hw/piix4.c
hw/pl011.c
hw/pl022.c
hw/ppc-viosrp.h [new file with mode: 0644]
hw/ppc.c
hw/ppc.h
hw/ppc440_bamboo.c
hw/ppc4xx_devs.c
hw/ppc4xx_pci.c
hw/ppc_newworld.c
hw/ppc_oldworld.c
hw/ppc_prep.c
hw/ppce500_mpc8544ds.c
hw/ppce500_pci.c
hw/ptimer.c
hw/pxa2xx.c
hw/pxa2xx_keypad.c
hw/pxa2xx_lcd.c
hw/qdev-properties.c
hw/qdev.c
hw/rc4030.c
hw/realview.c
hw/rtl8139.c
hw/s390-virtio-bus.c
hw/s390-virtio-bus.h
hw/s390-virtio.c
hw/sm501_template.h
hw/smbus.h
hw/smbus_eeprom.c
hw/spapr.c [new file with mode: 0644]
hw/spapr.h [new file with mode: 0644]
hw/spapr_hcall.c [new file with mode: 0644]
hw/spapr_llan.c [new file with mode: 0644]
hw/spapr_rtas.c [new file with mode: 0644]
hw/spapr_vio.c [new file with mode: 0644]
hw/spapr_vio.h [new file with mode: 0644]
hw/spapr_vscsi.c [new file with mode: 0644]
hw/spapr_vty.c [new file with mode: 0644]
hw/srp.h [new file with mode: 0644]
hw/stellaris.c
hw/stellaris_input.c
hw/strongarm.c [new file with mode: 0644]
hw/strongarm.h [new file with mode: 0644]
hw/sun4u.c
hw/syborg.c
hw/syborg_keyboard.c
hw/syborg_pointer.c
hw/syborg_rtc.c
hw/syborg_serial.c
hw/syborg_timer.c
hw/syborg_virtio.c
hw/sysbus.c
hw/tc58128.c
hw/tosa.c
hw/twl92230.c
hw/usb-ccid.c [new file with mode: 0644]
hw/usb-hid.c
hw/usb-msd.c
hw/usb-ohci.c
hw/versatilepb.c
hw/vexpress.c [new file with mode: 0644]
hw/virtio-9p-debug.c [deleted file]
hw/virtio-9p-debug.h [deleted file]
hw/virtio-9p-local.c [deleted file]
hw/virtio-9p-posix-acl.c [deleted file]
hw/virtio-9p-xattr-user.c [deleted file]
hw/virtio-9p-xattr.c [deleted file]
hw/virtio-9p-xattr.h [deleted file]
hw/virtio-9p.c [deleted file]
hw/virtio-9p.h [deleted file]
hw/virtio-balloon.c
hw/virtio-blk.c
hw/virtio-console.c
hw/virtio-pci.c
hw/virtio-serial-bus.c
hw/virtio.c
hw/vmport.c
hw/vt82c686.c
hw/xen_console.c
hw/xen_disk.c
hw/xen_domainbuild.c
hw/xen_machine_pv.c
hw/xenfb.c
hw/xics.c [new file with mode: 0644]
hw/xics.h [new file with mode: 0644]
hw/xilinx_timer.c
input.c
iohandler.c [new file with mode: 0644]
json-lexer.c
kvm-all.c
kvm-stub.c
libcacard/Makefile [new file with mode: 0644]
libcacard/cac.c [new file with mode: 0644]
libcacard/cac.h [new file with mode: 0644]
libcacard/card_7816.c [new file with mode: 0644]
libcacard/card_7816.h [new file with mode: 0644]
libcacard/card_7816t.h [new file with mode: 0644]
libcacard/event.c [new file with mode: 0644]
libcacard/eventt.h [new file with mode: 0644]
libcacard/link_test.c [new file with mode: 0644]
libcacard/vcard.c [new file with mode: 0644]
libcacard/vcard.h [new file with mode: 0644]
libcacard/vcard_emul.h [new file with mode: 0644]
libcacard/vcard_emul_nss.c [new file with mode: 0644]
libcacard/vcard_emul_type.c [new file with mode: 0644]
libcacard/vcard_emul_type.h [new file with mode: 0644]
libcacard/vcardt.h [new file with mode: 0644]
libcacard/vevent.h [new file with mode: 0644]
libcacard/vreader.c [new file with mode: 0644]
libcacard/vreader.h [new file with mode: 0644]
libcacard/vreadert.h [new file with mode: 0644]
libcacard/vscard_common.h [new file with mode: 0644]
libcacard/vscclient.c [new file with mode: 0644]
linux-user/alpha/syscall_nr.h
linux-user/arm/nwfpe/fpa11.c
linux-user/arm/nwfpe/fpa11.h
linux-user/arm/nwfpe/fpa11_cpdt.c
linux-user/arm/nwfpe/fpa11_cprt.c
linux-user/elfload.c
linux-user/ioctls.h
linux-user/main.c
linux-user/qemu.h
linux-user/strace.c
linux-user/strace.list
linux-user/syscall.c
linux-user/syscall_defs.h
linux-user/unicore32/syscall.h [new file with mode: 0644]
linux-user/unicore32/syscall_nr.h [new file with mode: 0644]
linux-user/unicore32/target_signal.h [new file with mode: 0644]
linux-user/unicore32/termbits.h [new file with mode: 0644]
migration-exec.c
migration-fd.c
migration-tcp.c
migration-unix.c
migration.h
monitor.c
nbd.c
nbd.h
net-checksum.c [deleted file]
net.c
net/dump.c
net/slirp.c
net/vde.c
os-posix.c
osdep.c
pc-bios/README
pc-bios/gpxe-eepro100-80861209.rom [deleted file]
pc-bios/pxe-e1000.bin [deleted file]
pc-bios/pxe-e1000.rom [new file with mode: 0644]
pc-bios/pxe-eepro100.rom [new file with mode: 0644]
pc-bios/pxe-ne2k_pci.bin [deleted file]
pc-bios/pxe-ne2k_pci.rom [new file with mode: 0644]
pc-bios/pxe-pcnet.bin [deleted file]
pc-bios/pxe-pcnet.rom [new file with mode: 0644]
pc-bios/pxe-rtl8139.bin [deleted file]
pc-bios/pxe-rtl8139.rom [new file with mode: 0644]
pc-bios/pxe-virtio.bin [deleted file]
pc-bios/pxe-virtio.rom [new file with mode: 0644]
pc-bios/slof.bin [new file with mode: 0644]
pc-bios/spapr-rtas.bin [new file with mode: 0644]
pc-bios/spapr-rtas/Makefile [new file with mode: 0644]
pc-bios/spapr-rtas/spapr-rtas.S [new file with mode: 0644]
qemu-char.c
qemu-char.h
qemu-common.h
qemu-config.c
qemu-error.c
qemu-img-cmds.hx
qemu-img.c
qemu-options.hx
qemu-os-win32.h
qemu-progress.c [new file with mode: 0644]
qemu-sockets.c
qemu-thread.h
qemu-timer.c
qemu-timer.h
qemu-tool.c
roms/SLOF [new submodule]
roms/ipxe [new submodule]
savevm.c
scripts/refresh-pxe-roms.sh [new file with mode: 0755]
scripts/tracetool
slirp/misc.c
spice-qemu-char.c
sysemu.h
target-alpha/op_helper.c
target-alpha/translate.c
target-arm/cpu.h
target-arm/helper.c
target-arm/helper.h [new file with mode: 0644]
target-arm/helpers.h [deleted file]
target-arm/iwmmxt_helper.c
target-arm/neon_helper.c
target-arm/op_helper.c
target-arm/translate.c
target-cris/op_helper.c
target-cris/translate.c
target-i386/cpuid.c
target-i386/exec.h
target-i386/helper.c
target-i386/kvm.c
target-i386/op_helper.c
target-i386/ops_sse.h
target-i386/translate.c
target-lm32/helper.c
target-lm32/lm32-decode.h [deleted file]
target-lm32/op_helper.c
target-lm32/translate.c
target-m68k/op_helper.c
target-m68k/translate.c
target-microblaze/cpu.h
target-microblaze/helper.h
target-microblaze/microblaze-decode.h
target-microblaze/op_helper.c
target-microblaze/translate.c
target-mips/cpu.h
target-mips/op_helper.c
target-mips/translate.c
target-ppc/cpu.h
target-ppc/helper.c
target-ppc/helper.h
target-ppc/kvm.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.h
target-s390x/exec.h
target-s390x/helper.c
target-s390x/kvm.c
target-s390x/op_helper.c
target-s390x/translate.c
target-sh4/helper.h
target-sh4/op_helper.c
target-sh4/translate.c
target-sparc/op_helper.c
target-sparc/translate.c
target-unicore32/cpu.h [new file with mode: 0644]
target-unicore32/exec.h [new file with mode: 0644]
target-unicore32/helper.c [new file with mode: 0644]
target-unicore32/helper.h [new file with mode: 0644]
target-unicore32/op_helper.c [new file with mode: 0644]
target-unicore32/translate.c [new file with mode: 0644]
tests/cris/check_openpf1.c
tests/cris/check_openpf2.c
tests/cris/check_stat3.c
tests/cris/check_stat4.c
tests/test-mmap.c
trace-events
translate-all.c
ui/sdl.c
ui/vnc-enc-tight.c
ui/vnc-enc-zlib.c
ui/vnc_keysym.h
usb-bsd.c
usb-linux.c
vl.c

index 1d7968062646bcb284e619be5a7dcb3149fbc7d3..08013fc57bef257b487f9535cd878008dcdefd8c 100644 (file)
@@ -44,6 +44,9 @@ QMP/qmp-commands.txt
 *.ky
 *.log
 *.pdf
+*.cps
+*.fns
+*.kys
 *.pg
 *.pyc
 *.toc
index 5217ce7d1cb1f19088a5d8a1b6542658280268d9..788447189e87cdd871e4f1f273803862fd629d21 100644 (file)
@@ -4,3 +4,9 @@
 [submodule "roms/seabios"]
        path = roms/seabios
        url = git://git.qemu.org/seabios.git/
+[submodule "roms/SLOF"]
+       path = roms/SLOF
+       url = git://git.qemu.org/SLOF.git
+[submodule "roms/ipxe"]
+       path = roms/ipxe
+       url = git://git.qemu.org/ipxe.git
index 9f3ff0e471da0d6b61ea50fc310125d7911bb454..e6f853dfff80de7ca392aeda052c592940a37af4 100644 (file)
@@ -214,6 +214,11 @@ M: Michael Walle <michael@walle.cc>
 S: Maintained
 F: hw/lm32_boards.c
 
+milkymist
+M: Michael Walle <michael@walle.cc>
+S: Maintained
+F: hw/milkymist.c
+
 M68K Machines
 -------------
 an5206
index 89e88b4a9e48256424d7bc8e255a29a650d89231..67c02687efc083d768465145ec6075cdc09306fe 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -112,38 +112,6 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
-ifeq ($(TRACE_BACKEND),dtrace)
-trace.h: trace.h-timestamp trace-dtrace.h
-else
-trace.h: trace.h-timestamp
-endif
-trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
-       $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
-       @cmp -s $@ trace.h || cp $@ trace.h
-
-trace.c: trace.c-timestamp
-trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
-       $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@,"  GEN   trace.c")
-       @cmp -s $@ trace.c || cp $@ trace.c
-
-trace.o: trace.c $(GENERATED_HEADERS)
-
-trace-dtrace.h: trace-dtrace.dtrace
-       $(call quiet-command,dtrace -o $@ -h -s $<, "  GEN   trace-dtrace.h")
-
-# Normal practice is to name DTrace probe file with a '.d' extension
-# but that gets picked up by QEMU's Makefile as an external dependancy
-# rule file. So we use '.dtrace' instead
-trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
-trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
-       $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
-       @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
-
-trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
-       $(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")
-
-simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
-
 version.o: $(SRC_PATH)/version.rc config-host.mak
        $(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
 
@@ -173,6 +141,8 @@ check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
 check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
 check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
 
+QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
+
 clean:
 # avoid old build problems by removing potentially incorrect old files
        rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
@@ -184,7 +154,7 @@ clean:
        rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
        rm -f trace-dtrace.h trace-dtrace.h-timestamp
        $(MAKE) -C tests clean
-       for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
+       for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
        if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
        rm -f $$d/qemu-options.def; \
         done
@@ -193,9 +163,12 @@ distclean: clean
        rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
        rm -f config-all-devices.mak
        rm -f roms/seabios/config.mak roms/vgabios/config.mak
-       rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr
+       rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
+       rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
+       rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
+       rm -f qemu-doc.vr
        rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
-       for d in $(TARGET_DIRS) libhw32 libhw64 libuser libdis libdis-user; do \
+       for d in $(TARGET_DIRS) $(QEMULIBS); do \
        rm -rf $$d || exit 1 ; \
         done
 
@@ -207,13 +180,12 @@ ifdef INSTALL_BLOBS
 BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
 vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
 ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
-gpxe-eepro100-80861209.rom \
-pxe-e1000.bin \
-pxe-ne2k_pci.bin pxe-pcnet.bin \
-pxe-rtl8139.bin pxe-virtio.bin \
+pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
+pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
 bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
 multiboot.bin linuxboot.bin \
-s390-zipl.rom
+s390-zipl.rom \
+spapr-rtas.bin slof.bin
 else
 BLOBS=
 endif
@@ -355,10 +327,12 @@ tarbin:
        $(datadir)/openbios-sparc32 \
        $(datadir)/openbios-sparc64 \
        $(datadir)/openbios-ppc \
-       $(datadir)/pxe-ne2k_pci.bin \
-       $(datadir)/pxe-rtl8139.bin \
-       $(datadir)/pxe-pcnet.bin \
-       $(datadir)/pxe-e1000.bin \
+       $(datadir)/pxe-e1000.rom \
+       $(datadir)/pxe-eepro100.rom \
+       $(datadir)/pxe-ne2k_pci.rom \
+       $(datadir)/pxe-pcnet.rom \
+       $(datadir)/pxe-rtl8139.rom \
+       $(datadir)/pxe-virtio.rom \
        $(docdir)/qemu-doc.html \
        $(docdir)/qemu-tech.html \
        $(mandir)/man1/qemu.1 \
index f8cf199e1485f48dac89b6d975de3fde615eebd2..9d8851e5d47ebe52f2a649478ea135b0e22d9425 100644 (file)
@@ -14,7 +14,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o
 # block-obj-y is code used by both qemu system emulation and qemu-img
 
 block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
-block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o
+block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
@@ -94,11 +94,11 @@ common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
 common-obj-$(CONFIG_SD) += sd.o
 common-obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
 common-obj-y += bt-hci-csr.o
-common-obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
+common-obj-y += buffered_file.o migration.o migration-tcp.o
 common-obj-y += qemu-char.o savevm.o #aio.o
 common-obj-y += msmouse.o ps2.o
 common-obj-y += qdev.o qdev-properties.o
-common-obj-y += block-migration.o
+common-obj-y += block-migration.o iohandler.o
 common-obj-y += pflib.o
 common-obj-y += bitmap.o bitops.o
 
@@ -200,6 +200,8 @@ hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
 hw-obj-$(CONFIG_DMA) += dma.o
 hw-obj-$(CONFIG_HPET) += hpet.o
 hw-obj-$(CONFIG_APPLESMC) += applesmc.o
+hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
+hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
 
 # PPC devices
 hw-obj-$(CONFIG_OPENPIC) += openpic.o
@@ -240,7 +242,7 @@ hw-obj-$(CONFIG_LAN9118) += lan9118.o
 hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
 
 # IDE
-hw-obj-$(CONFIG_IDE_CORE) += ide/core.o
+hw-obj-$(CONFIG_IDE_CORE) += ide/core.o ide/atapi.o
 hw-obj-$(CONFIG_IDE_QDEV) += ide/qdev.o
 hw-obj-$(CONFIG_IDE_PCI) += ide/pci.o
 hw-obj-$(CONFIG_IDE_ISA) += ide/isa.o
@@ -283,9 +285,13 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
 adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 
-hw-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p-debug.o
-hw-obj-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
-hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
+9pfs-nested-$(CONFIG_REALLY_VIRTFS) = virtio-9p-debug.o
+9pfs-nested-$(CONFIG_VIRTFS) +=  virtio-9p-local.o virtio-9p-xattr.o
+9pfs-nested-$(CONFIG_VIRTFS) +=   virtio-9p-xattr-user.o virtio-9p-posix-acl.o
+
+hw-obj-$(CONFIG_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
+$(addprefix 9pfs/, $(9pfs-nested-y)): CFLAGS +=  -I$(SRC_PATH)/hw/
+
 
 ######################################################################
 # libdis
@@ -309,6 +315,38 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
 ######################################################################
 # trace
 
+ifeq ($(TRACE_BACKEND),dtrace)
+trace.h: trace.h-timestamp trace-dtrace.h
+else
+trace.h: trace.h-timestamp
+endif
+trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
+       $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
+       @cmp -s $@ trace.h || cp $@ trace.h
+
+trace.c: trace.c-timestamp
+trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
+       $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@,"  GEN   trace.c")
+       @cmp -s $@ trace.c || cp $@ trace.c
+
+trace.o: trace.c $(GENERATED_HEADERS)
+
+trace-dtrace.h: trace-dtrace.dtrace
+       $(call quiet-command,dtrace -o $@ -h -s $<, "  GEN   trace-dtrace.h")
+
+# Normal practice is to name DTrace probe file with a '.d' extension
+# but that gets picked up by QEMU's Makefile as an external dependancy
+# rule file. So we use '.dtrace' instead
+trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
+trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
+       $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
+       @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
+
+trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
+       $(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")
+
+simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
+
 ifeq ($(TRACE_BACKEND),dtrace)
 trace-obj-y = trace-dtrace.o
 else
@@ -319,6 +357,11 @@ user-obj-y += qemu-timer-common.o
 endif
 endif
 
+######################################################################
+# smartcard
+
+libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
+
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
index 62b102a7f8a07c8065613381dd206dd0193dde5f..21f864afd2e2b789964cfc93a75096a0b63f5692 100644 (file)
@@ -94,7 +94,7 @@ tcg/tcg.o: cpu.h
 
 # HELPER_CFLAGS is used for all the code compiled with static register
 # variables
-op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+%_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 
 # Note: this is a workaround. The real fix is to avoid compiling
 # cpu_signal_handler() in cpu-exec.c.
@@ -194,7 +194,7 @@ obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial
 obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 obj-y += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o
+obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p.o
 obj-y += rwhandler.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
@@ -209,7 +209,13 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 
 # Inter-VM PCI shared memory
-obj-$(CONFIG_KVM) += ivshmem.o
+CONFIG_IVSHMEM =
+ifeq ($(CONFIG_KVM), y)
+  ifeq ($(CONFIG_PCI), y)
+    CONFIG_IVSHMEM = y
+  endif
+endif
+obj-$(CONFIG_IVSHMEM) += ivshmem.o
 
 # Hardware support
 obj-i386-y += vga.o
@@ -231,6 +237,11 @@ obj-ppc-y += ppc_prep.o
 obj-ppc-y += ppc_oldworld.o
 # NewWorld PowerMac
 obj-ppc-y += ppc_newworld.o
+# IBM pSeries (sPAPR)
+ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy)
+obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
+obj-ppc-y += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
+endif
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
@@ -249,6 +260,7 @@ obj-ppc-y += xilinx_ethlite.o
 
 # LM32 boards
 obj-lm32-y += lm32_boards.o
+obj-lm32-y += milkymist.o
 
 # LM32 peripherals
 obj-lm32-y += lm32_pic.o
@@ -256,6 +268,17 @@ obj-lm32-y += lm32_juart.o
 obj-lm32-y += lm32_timer.o
 obj-lm32-y += lm32_uart.o
 obj-lm32-y += lm32_sys.o
+obj-lm32-y += milkymist-ac97.o
+obj-lm32-y += milkymist-hpdmc.o
+obj-lm32-y += milkymist-memcard.o
+obj-lm32-y += milkymist-minimac2.o
+obj-lm32-y += milkymist-pfpu.o
+obj-lm32-y += milkymist-softusb.o
+obj-lm32-y += milkymist-sysctl.o
+obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o
+obj-lm32-y += milkymist-uart.o
+obj-lm32-y += milkymist-vgafb.o
+obj-lm32-y += framebuffer.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
@@ -328,6 +351,9 @@ obj-arm-y += framebuffer.o
 obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
 obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
 obj-arm-y += syborg_virtio.o
+obj-arm-y += vexpress.o
+obj-arm-y += strongarm.o
+obj-arm-y += collie.o
 
 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
@@ -353,6 +379,12 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
 
 endif # CONFIG_SOFTMMU
 
+ifndef CONFIG_LINUX_USER
+# libcacard needs qemu-thread support, and besides is only needed by devices
+# so not requires with linux-user targets
+obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y))
+endif # CONFIG_LINUX_USER
+
 obj-y += $(addprefix ../, $(trace-obj-y))
 obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
@@ -369,9 +401,11 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
 qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
        $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 
+9pfs/virtio-9p.o: CFLAGS +=  -I$(SRC_PATH)/hw/
+
 clean:
        rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
-       rm -f *.d */*.d tcg/*.o ide/*.o
+       rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
        rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
 ifdef CONFIG_SYSTEMTAP_TRACE
        rm -f *.stp
diff --git a/acl.c b/acl.c
index 311dade4e25d517e371a67712741c62206321d78..82c27043c1f2560499b15591b35b933a4022b3e8 100644 (file)
--- a/acl.c
+++ b/acl.c
@@ -24,7 +24,6 @@
 
 
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "acl.h"
 
 #ifdef CONFIG_FNMATCH
index c83360c3a68268e210c46c19d00a82eef6b727cf..86ebc149bc0423053e9211d495429a5959d31160 100644 (file)
@@ -22,8 +22,6 @@ enum {
 extern const uint32_t arch_type;
 
 void select_soundhw(const char *optarg);
-int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque);
-int ram_load(QEMUFile *f, void *opaque, int version_id);
 void do_acpitable_option(const char *optarg);
 void do_smbios_option(const char *optarg);
 void cpudef_init(void);
index 1d5179b601e7419a80213612bb28c6f85727fcac..e9e6f8993f11bc630e3b9e8825caea068c7065f0 100644 (file)
@@ -33,7 +33,6 @@
 #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
 #else
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "gdbstub.h"
 #endif
 
index b74dcfa73470c9ad28097303a4b34344319d259e..a847aa90f7fd1999e5afcf009f5c371446061526 100644 (file)
@@ -139,36 +139,36 @@ static int aud_to_sdlfmt (audfmt_e fmt)
     }
 }
 
-static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
+static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness)
 {
     switch (sdlfmt) {
     case AUDIO_S8:
-        *endianess = 0;
+        *endianness = 0;
         *fmt = AUD_FMT_S8;
         break;
 
     case AUDIO_U8:
-        *endianess = 0;
+        *endianness = 0;
         *fmt = AUD_FMT_U8;
         break;
 
     case AUDIO_S16LSB:
-        *endianess = 0;
+        *endianness = 0;
         *fmt = AUD_FMT_S16;
         break;
 
     case AUDIO_U16LSB:
-        *endianess = 0;
+        *endianness = 0;
         *fmt = AUD_FMT_U16;
         break;
 
     case AUDIO_S16MSB:
-        *endianess = 1;
+        *endianness = 1;
         *fmt = AUD_FMT_S16;
         break;
 
     case AUDIO_U16MSB:
-        *endianess = 1;
+        *endianness = 1;
         *fmt = AUD_FMT_U16;
         break;
 
@@ -338,7 +338,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
     SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
     SDLAudioState *s = &glob_sdl;
     SDL_AudioSpec req, obt;
-    int endianess;
+    int endianness;
     int err;
     audfmt_e effective_fmt;
     struct audsettings obt_as;
@@ -354,7 +354,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
         return -1;
     }
 
-    err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
+    err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
     if (err) {
         sdl_close (s);
         return -1;
@@ -363,7 +363,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.channels;
     obt_as.fmt = effective_fmt;
-    obt_as.endianness = endianess;
+    obt_as.endianness = endianness;
 
     audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = obt.samples;
index 0021fef4b83182c0e113f3f1b6e87138ac010e8f..248c1b50a97ed0ef71415cf9d43d65a1f291522a 100644 (file)
--- a/balloon.c
+++ b/balloon.c
@@ -22,7 +22,6 @@
  * THE SOFTWARE.
  */
 
-#include "sysemu.h"
 #include "monitor.h"
 #include "qjson.h"
 #include "qint.h"
index 8218bac09c6cd30286a4ce5b826ac378700036da..8d06a23649991ff21e6917bb0f9b949f87eecbc2 100644 (file)
@@ -62,7 +62,6 @@ typedef struct BlkMigBlock {
     QEMUIOVector qiov;
     BlockDriverAIOCB *aiocb;
     int ret;
-    int64_t time;
     QSIMPLEQ_ENTRY(BlkMigBlock) entry;
 } BlkMigBlock;
 
@@ -78,6 +77,7 @@ typedef struct BlkMigState {
     int prev_progress;
     int bulk_completed;
     long double total_time;
+    long double prev_time_offset;
     int reads;
 } BlkMigState;
 
@@ -131,16 +131,10 @@ uint64_t blk_mig_bytes_total(void)
     return sum << BDRV_SECTOR_BITS;
 }
 
-static inline void add_avg_read_time(int64_t time)
-{
-    block_mig_state.reads++;
-    block_mig_state.total_time += time;
-}
-
 static inline long double compute_read_bwidth(void)
 {
     assert(block_mig_state.total_time != 0);
-    return  (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time;
+    return (block_mig_state.reads / block_mig_state.total_time) * BLOCK_SIZE;
 }
 
 static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
@@ -191,13 +185,14 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds)
 
 static void blk_mig_read_cb(void *opaque, int ret)
 {
+    long double curr_time = qemu_get_clock_ns(rt_clock);
     BlkMigBlock *blk = opaque;
 
     blk->ret = ret;
 
-    blk->time = qemu_get_clock_ns(rt_clock) - blk->time;
-
-    add_avg_read_time(blk->time);
+    block_mig_state.reads++;
+    block_mig_state.total_time += (curr_time - block_mig_state.prev_time_offset);
+    block_mig_state.prev_time_offset = curr_time;
 
     QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
     bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
@@ -250,7 +245,9 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
     blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
     qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
 
-    blk->time = qemu_get_clock_ns(rt_clock);
+    if (block_mig_state.submitted == 0) {
+        block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
+    }
 
     blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
                                 nr_sectors, blk_mig_read_cb, blk);
@@ -409,7 +406,9 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
                 blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
                 qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
 
-                blk->time = qemu_get_clock_ns(rt_clock);
+                if (block_mig_state.submitted == 0) {
+                    block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
+                }
 
                 blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
                                             nr_sectors, blk_mig_read_cb, blk);
diff --git a/block.c b/block.c
index c8e2f97614a7217b7e1ae309bfc5ee1bf9714c49..f731c7afbfaf6467e4df66c1bb8b55aa69918c69 100644 (file)
--- a/block.c
+++ b/block.c
@@ -697,14 +697,22 @@ void bdrv_close_all(void)
     }
 }
 
+/* make a BlockDriverState anonymous by removing from bdrv_state list.
+   Also, NULL terminate the device_name to prevent double remove */
+void bdrv_make_anon(BlockDriverState *bs)
+{
+    if (bs->device_name[0] != '\0') {
+        QTAILQ_REMOVE(&bdrv_states, bs, list);
+    }
+    bs->device_name[0] = '\0';
+}
+
 void bdrv_delete(BlockDriverState *bs)
 {
     assert(!bs->peer);
 
     /* remove from list, if necessary */
-    if (bs->device_name[0] != '\0') {
-        QTAILQ_REMOVE(&bdrv_states, bs, list);
-    }
+    bdrv_make_anon(bs);
 
     bdrv_close(bs);
     if (bs->file != NULL) {
@@ -1153,14 +1161,12 @@ int64_t bdrv_getlength(BlockDriverState *bs)
     if (!drv)
         return -ENOMEDIUM;
 
-    /* Fixed size devices use the total_sectors value for speed instead of
-       issuing a length query (like lseek) on each call.  Also, legacy block
-       drivers don't provide a bdrv_getlength function and must use
-       total_sectors. */
-    if (!bs->growable || !drv->bdrv_getlength) {
-        return bs->total_sectors * BDRV_SECTOR_SIZE;
+    if (bs->growable || bs->removable) {
+        if (drv->bdrv_getlength) {
+            return drv->bdrv_getlength(bs);
+        }
     }
-    return drv->bdrv_getlength(bs);
+    return bs->total_sectors * BDRV_SECTOR_SIZE;
 }
 
 /* return 0 as number of sectors if no device present or error */
@@ -2809,6 +2815,8 @@ void bdrv_set_locked(BlockDriverState *bs, int locked)
 {
     BlockDriver *drv = bs->drv;
 
+    trace_bdrv_set_locked(bs, locked);
+
     bs->locked = locked;
     if (drv && drv->bdrv_set_locked) {
         drv->bdrv_set_locked(bs, locked);
diff --git a/block.h b/block.h
index 5d78fc0ed7076f52e7d872f79aa012a8620d796a..52e9cad55c0e2ce50fdcfdfeca49f71cdd75a82c 100644 (file)
--- a/block.h
+++ b/block.h
@@ -66,6 +66,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
     QEMUOptionParameter *options);
 int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
 BlockDriverState *bdrv_new(const char *device_name);
+void bdrv_make_anon(BlockDriverState *bs);
 void bdrv_delete(BlockDriverState *bs);
 int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
 int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
index c8dc763c6bb4dd5d7f21258de1fac7edeeb9b54a..7a52f62e7e1fb0e0af949b6ec3590b78d421ed1d 100644 (file)
 #include "qemu-common.h"
 #include "nbd.h"
 #include "module.h"
+#include "qemu_socket.h"
 
 #include <sys/types.h>
 #include <unistd.h>
 
 #define EN_OPTSTR ":exportname="
 
+/* #define DEBUG_NBD */
+
+#if defined(DEBUG_NBD)
+#define logout(fmt, ...) \
+                fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
 typedef struct BDRVNBDState {
     int sock;
     off_t size;
     size_t blocksize;
+    char *export_name; /* An NBD server may export several devices */
+
+    /* If it begins with  '/', this is a UNIX domain socket. Otherwise,
+     * it's a string of the form <hostname|ip4|\[ip6\]>:port
+     */
+    char *host_spec;
 } BDRVNBDState;
 
-static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
 {
-    BDRVNBDState *s = bs->opaque;
-    uint32_t nbdflags;
-
     char *file;
-    char *name;
-    const char *host;
+    char *export_name;
+    const char *host_spec;
     const char *unixpath;
-    int sock;
-    off_t size;
-    size_t blocksize;
-    int ret;
     int err = -EINVAL;
 
     file = qemu_strdup(filename);
 
-    name = strstr(file, EN_OPTSTR);
-    if (name) {
-        if (name[strlen(EN_OPTSTR)] == 0) {
+    export_name = strstr(file, EN_OPTSTR);
+    if (export_name) {
+        if (export_name[strlen(EN_OPTSTR)] == 0) {
             goto out;
         }
-        name[0] = 0;
-        name += strlen(EN_OPTSTR);
+        export_name[0] = 0; /* truncate 'file' */
+        export_name += strlen(EN_OPTSTR);
+        s->export_name = qemu_strdup(export_name);
     }
 
-    if (!strstart(file, "nbd:", &host)) {
+    /* extract the host_spec - fail if it's not nbd:... */
+    if (!strstart(file, "nbd:", &host_spec)) {
         goto out;
     }
 
-    if (strstart(host, "unix:", &unixpath)) {
-
-        if (unixpath[0] != '/') {
+    /* are we a UNIX or TCP socket? */
+    if (strstart(host_spec, "unix:", &unixpath)) {
+        if (unixpath[0] != '/') { /* We demand  an absolute path*/
             goto out;
         }
-
-        sock = unix_socket_outgoing(unixpath);
-
+        s->host_spec = qemu_strdup(unixpath);
     } else {
-        uint16_t port = NBD_DEFAULT_PORT;
-        char *p, *r;
-        char hostname[128];
+        s->host_spec = qemu_strdup(host_spec);
+    }
 
-        pstrcpy(hostname, 128, host);
+    err = 0;
 
-        p = strchr(hostname, ':');
-        if (p != NULL) {
-            *p = '\0';
-            p++;
+out:
+    qemu_free(file);
+    if (err != 0) {
+        qemu_free(s->export_name);
+        qemu_free(s->host_spec);
+    }
+    return err;
+}
 
-            port = strtol(p, &r, 0);
-            if (r == p) {
-                goto out;
-            }
-        }
+static int nbd_establish_connection(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+    int sock;
+    int ret;
+    off_t size;
+    size_t blocksize;
+    uint32_t nbdflags;
 
-        sock = tcp_socket_outgoing(hostname, port);
+    if (s->host_spec[0] == '/') {
+        sock = unix_socket_outgoing(s->host_spec);
+    } else {
+        sock = tcp_socket_outgoing_spec(s->host_spec);
     }
 
+    /* Failed to establish connection */
     if (sock == -1) {
-        err = -errno;
-        goto out;
+        logout("Failed to establish connection to NBD server\n");
+        return -errno;
     }
 
-    ret = nbd_receive_negotiate(sock, name, &nbdflags, &size, &blocksize);
+    /* NBD handshake */
+    ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size,
+                                &blocksize);
     if (ret == -1) {
-        err = -errno;
-        goto out;
+        logout("Failed to negotiate with the NBD server\n");
+        closesocket(sock);
+        return -errno;
     }
 
+    /* Now that we're connected, set the socket to be non-blocking */
+    socket_set_nonblock(sock);
+
     s->sock = sock;
     s->size = size;
     s->blocksize = blocksize;
-    err = 0;
 
-out:
-    qemu_free(file);
-    return err;
+    logout("Established connection with NBD server\n");
+    return 0;
+}
+
+static void nbd_teardown_connection(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+    struct nbd_request request;
+
+    request.type = NBD_CMD_DISC;
+    request.handle = (uint64_t)(intptr_t)bs;
+    request.from = 0;
+    request.len = 0;
+    nbd_send_request(s->sock, &request);
+
+    closesocket(s->sock);
+}
+
+static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+{
+    BDRVNBDState *s = bs->opaque;
+    int result;
+
+    /* Pop the config into our state object. Exit if invalid. */
+    result = nbd_config(s, filename, flags);
+    if (result != 0) {
+        return result;
+    }
+
+    /* establish TCP connection, return error if it fails
+     * TODO: Configurable retry-until-timeout behaviour.
+     */
+    result = nbd_establish_connection(bs);
+
+    return result;
 }
 
 static int nbd_read(BlockDriverState *bs, int64_t sector_num,
@@ -184,15 +240,10 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num,
 static void nbd_close(BlockDriverState *bs)
 {
     BDRVNBDState *s = bs->opaque;
-    struct nbd_request request;
-
-    request.type = NBD_CMD_DISC;
-    request.handle = (uint64_t)(intptr_t)bs;
-    request.from = 0;
-    request.len = 0;
-    nbd_send_request(s->sock, &request);
+    qemu_free(s->export_name);
+    qemu_free(s->host_spec);
 
-    close(s->sock);
+    nbd_teardown_connection(bs);
 }
 
 static int64_t nbd_getlength(BlockDriverState *bs)
index 4600932bf27372e95ffbb095ce332f1035244593..22cd07fa1fe6697e354f84f1d9fff506385abf45 100644 (file)
@@ -18,7 +18,7 @@ typedef struct {
     BdrvCheckResult *result;
     bool fix;                           /* whether to fix invalid offsets */
 
-    size_t nclusters;
+    uint64_t nclusters;
     uint32_t *used_clusters;            /* referenced cluster bitmap */
 
     QEDRequest request;
@@ -72,7 +72,8 @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
     for (i = 0; i < s->table_nelems; i++) {
         uint64_t offset = table->offsets[i];
 
-        if (!offset) {
+        if (qed_offset_is_unalloc_cluster(offset) ||
+            qed_offset_is_zero_cluster(offset)) {
             continue;
         }
 
@@ -111,7 +112,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
         unsigned int num_invalid_l2;
         uint64_t offset = table->offsets[i];
 
-        if (!offset) {
+        if (qed_offset_is_unalloc_cluster(offset)) {
             continue;
         }
 
@@ -176,7 +177,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
 static void qed_check_for_leaks(QEDCheck *check)
 {
     BDRVQEDState *s = check->s;
-    size_t i;
+    uint64_t i;
 
     for (i = s->header.header_size; i < check->nclusters; i++) {
         if (!qed_test_bit(check->used_clusters, i)) {
index 0ec864b14cda0f9cc6b3821fac0a10fc58b7039a..3e19ad1766c24582d903c2e56a80b692ce39b0cf 100644 (file)
@@ -23,7 +23,8 @@
  * @n:              Maximum number of clusters
  * @offset:         Set to first cluster offset
  *
- * This function scans tables for contiguous allocated or free clusters.
+ * This function scans tables for contiguous clusters.  A contiguous run of
+ * clusters may be allocated, unallocated, or zero.
  */
 static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
                                                   QEDTable *table,
@@ -38,9 +39,14 @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
     *offset = last;
 
     for (i = index + 1; i < end; i++) {
-        if (last == 0) {
-            /* Counting free clusters */
-            if (table->offsets[i] != 0) {
+        if (qed_offset_is_unalloc_cluster(last)) {
+            /* Counting unallocated clusters */
+            if (!qed_offset_is_unalloc_cluster(table->offsets[i])) {
+                break;
+            }
+        } else if (qed_offset_is_zero_cluster(last)) {
+            /* Counting zero clusters */
+            if (!qed_offset_is_zero_cluster(table->offsets[i])) {
                 break;
             }
         } else {
@@ -87,14 +93,19 @@ static void qed_find_cluster_cb(void *opaque, int ret)
     n = qed_count_contiguous_clusters(s, request->l2_table->table,
                                       index, n, &offset);
 
-    ret = offset ? QED_CLUSTER_FOUND : QED_CLUSTER_L2;
-    len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
-              qed_offset_into_cluster(s, find_cluster_cb->pos));
-
-    if (offset && !qed_check_cluster_offset(s, offset)) {
+    if (qed_offset_is_unalloc_cluster(offset)) {
+        ret = QED_CLUSTER_L2;
+    } else if (qed_offset_is_zero_cluster(offset)) {
+        ret = QED_CLUSTER_ZERO;
+    } else if (qed_check_cluster_offset(s, offset)) {
+        ret = QED_CLUSTER_FOUND;
+    } else {
         ret = -EINVAL;
     }
 
+    len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
+              qed_offset_into_cluster(s, find_cluster_cb->pos));
+
 out:
     find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
     qemu_free(find_cluster_cb);
@@ -132,7 +143,7 @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
     len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
 
     l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
-    if (!l2_offset) {
+    if (qed_offset_is_unalloc_cluster(l2_offset)) {
         cb(opaque, QED_CLUSTER_L1, 0, len);
         return;
     }
index 75ae2440ee44ce7c9a69b1fc3095ae112cb21a1d..c8c59304480a745f67dcd818bd27457bea2ccc6f 100644 (file)
@@ -573,7 +573,7 @@ static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l
 {
     QEDIsAllocatedCB *cb = opaque;
     *cb->pnum = len / BDRV_SECTOR_SIZE;
-    cb->is_allocated = ret == QED_CLUSTER_FOUND;
+    cb->is_allocated = (ret == QED_CLUSTER_FOUND || ret == QED_CLUSTER_ZERO);
 }
 
 static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
@@ -745,7 +745,10 @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
  * @table:          L2 table
  * @index:          First cluster index
  * @n:              Number of contiguous clusters
- * @cluster:        First cluster byte offset in image file
+ * @cluster:        First cluster offset
+ *
+ * The cluster offset may be an allocated byte offset in the image file, the
+ * zero cluster marker, or the unallocated cluster marker.
  */
 static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
                                 unsigned int n, uint64_t cluster)
@@ -753,7 +756,10 @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
     int i;
     for (i = index; i < index + n; i++) {
         table->offsets[i] = cluster;
-        cluster += s->header.cluster_size;
+        if (!qed_offset_is_unalloc_cluster(cluster) &&
+            !qed_offset_is_zero_cluster(cluster)) {
+            cluster += s->header.cluster_size;
+        }
     }
 }
 
@@ -1075,6 +1081,7 @@ static void qed_aio_write_data(void *opaque, int ret,
 
     case QED_CLUSTER_L2:
     case QED_CLUSTER_L1:
+    case QED_CLUSTER_ZERO:
         qed_aio_write_alloc(acb, len);
         break;
 
@@ -1114,8 +1121,12 @@ static void qed_aio_read_data(void *opaque, int ret,
 
     qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
 
-    /* Handle backing file and unallocated sparse hole reads */
-    if (ret != QED_CLUSTER_FOUND) {
+    /* Handle zero cluster and backing file reads */
+    if (ret == QED_CLUSTER_ZERO) {
+        qemu_iovec_memset(&acb->cur_qiov, 0, acb->cur_qiov.size);
+        qed_aio_next_io(acb, 0);
+        return;
+    } else if (ret != QED_CLUSTER_FOUND) {
         qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
                               qed_aio_next_io, acb);
         return;
index 2925e37b1cd942f954874ee0c8e41950eb502fe9..1d1421fee1230e3c7f0262939cd878cae779cac6 100644 (file)
@@ -161,6 +161,7 @@ typedef struct {
 
 enum {
     QED_CLUSTER_FOUND,         /* cluster found */
+    QED_CLUSTER_ZERO,          /* zero cluster found */
     QED_CLUSTER_L2,            /* cluster missing in L2 */
     QED_CLUSTER_L1,            /* cluster missing in L1 */
 };
@@ -251,7 +252,7 @@ static inline uint64_t qed_offset_into_cluster(BDRVQEDState *s, uint64_t offset)
     return offset & (s->header.cluster_size - 1);
 }
 
-static inline unsigned int qed_bytes_to_clusters(BDRVQEDState *s, size_t bytes)
+static inline uint64_t qed_bytes_to_clusters(BDRVQEDState *s, uint64_t bytes)
 {
     return qed_start_of_cluster(s, bytes + (s->header.cluster_size - 1)) /
            (s->header.cluster_size - 1);
@@ -298,4 +299,29 @@ static inline bool qed_check_table_offset(BDRVQEDState *s, uint64_t offset)
            qed_check_cluster_offset(s, end_offset);
 }
 
+static inline bool qed_offset_is_cluster_aligned(BDRVQEDState *s,
+                                                 uint64_t offset)
+{
+    if (qed_offset_into_cluster(s, offset)) {
+        return false;
+    }
+    return true;
+}
+
+static inline bool qed_offset_is_unalloc_cluster(uint64_t offset)
+{
+    if (offset == 0) {
+        return true;
+    }
+    return false;
+}
+
+static inline bool qed_offset_is_zero_cluster(uint64_t offset)
+{
+    if (offset == 1) {
+        return true;
+    }
+    return false;
+}
+
 #endif /* BLOCK_QED_H */
index a54e0dee3186dcdb7431371e2800d53c8020658e..98946d72b75b091dfee8ccdb2d5fc8fa67b755c7 100644 (file)
@@ -13,6 +13,7 @@
 #include "qemu-error.h"
 #include "qemu_socket.h"
 #include "block_int.h"
+#include "bitops.h"
 
 #define SD_PROTO_VER 0x01
 
@@ -1829,20 +1830,6 @@ static int sd_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
     return 0;
 }
 
-#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-#define BITS_PER_BYTE        8
-#define BITS_TO_LONGS(nr)    DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
-#define DECLARE_BITMAP(name,bits)               \
-    unsigned long name[BITS_TO_LONGS(bits)]
-
-#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long))
-
-static inline int test_bit(unsigned int nr, const unsigned long *addr)
-{
-    return ((1UL << (nr % BITS_PER_LONG)) &
-            (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
-}
-
 static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 {
     BDRVSheepdogState *s = bs->opaque;
index 90540792d316db9cd684cc4dd1dc9e58f152ace6..701745bf8c7fb7c4d6d1dfd042894acf1d0a4c9a 100644 (file)
@@ -113,7 +113,7 @@ void uuid_unparse(const uuid_t uu, char *out);
  */
 #define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
 
-/* Unallocated blocks use this index (no need to convert endianess). */
+/* Unallocated blocks use this index (no need to convert endianness). */
 #define VDI_UNALLOCATED UINT32_MAX
 
 #if !defined(CONFIG_UUID)
@@ -194,7 +194,7 @@ typedef struct {
     uint32_t block_sectors;
     /* First sector of block map. */
     uint32_t bmap_sector;
-    /* VDI header (converted to host endianess). */
+    /* VDI header (converted to host endianness). */
     VdiHeader header;
 } BDRVVdiState;
 
index 7b025be01d967fc4b8a3bfe99140542118e52aa5..56865da5bc414cd168fac1ae2f0dc96563e961b9 100644 (file)
@@ -505,12 +505,8 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
     int ret = -EIO;
 
     // Read out options
-    while (options && options->name) {
-        if (!strcmp(options->name, "size")) {
-            total_sectors = options->value.n / 512;
-        }
-        options++;
-    }
+    total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n /
+                    BDRV_SECTOR_SIZE;
 
     // Create the file
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
index ecf2252d83c468e35352a8b84948c61e573ec1d9..5429621f0c29745509739f9b996a92e1d34754ef 100644 (file)
@@ -503,7 +503,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
     case IF_VIRTIO:
         /* add virtio block device */
         opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
-        qemu_opt_set(opts, "driver", "virtio-blk-pci");
+        qemu_opt_set(opts, "driver", "virtio-blk");
         qemu_opt_set(opts, "drive", dinfo->id);
         if (devaddr)
             qemu_opt_set(opts, "addr", devaddr);
@@ -737,8 +737,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *id = qdict_get_str(qdict, "id");
     BlockDriverState *bs;
-    BlockDriverState **ptr;
-    Property *prop;
 
     bs = bdrv_find(id);
     if (!bs) {
@@ -755,24 +753,17 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     bdrv_flush(bs);
     bdrv_close(bs);
 
-    /* clean up guest state from pointing to host resource by
-     * finding and removing DeviceState "drive" property */
+    /* if we have a device associated with this BlockDriverState (bs->peer)
+     * then we need to make the drive anonymous until the device
+     * can be removed.  If this is a drive with no device backing
+     * then we can just get rid of the block driver state right here.
+     */
     if (bs->peer) {
-        for (prop = bs->peer->info->props; prop && prop->name; prop++) {
-            if (prop->info->type == PROP_TYPE_DRIVE) {
-                ptr = qdev_get_prop_ptr(bs->peer, prop);
-                if (*ptr == bs) {
-                    bdrv_detach(bs, bs->peer);
-                    *ptr = NULL;
-                    break;
-                }
-            }
-        }
+        bdrv_make_anon(bs);
+    } else {
+        drive_uninit(drive_get_by_blockdev(bs));
     }
 
-    /* clean up host side */
-    drive_uninit(drive_get_by_blockdev(bs));
-
     return 0;
 }
 
index 6931e7cc62a9d000d5738cd3f33dd49100be2257..095254ddc6ef350e5f5e7f1f8b41ce0faa48b24f 100644 (file)
--- a/bt-host.c
+++ b/bt-host.c
@@ -19,7 +19,6 @@
 
 #include "qemu-common.h"
 #include "qemu-char.h"
-#include "sysemu.h"
 #include "net.h"
 #include "bt-host.h"
 
index 679c5e05d7da30ef6c03adab098389061e77565d..3c5772093efc340e4d60f86e093fb8318c2ed141 100644 (file)
--- a/bt-vhci.c
+++ b/bt-vhci.c
@@ -19,7 +19,6 @@
 
 #include "qemu-common.h"
 #include "qemu-char.h"
-#include "sysemu.h"
 #include "net.h"
 #include "hw/bt.h"
 
index b5e2baff46be925646a9f35ae4af2f58bf8f2ba7..41b42c3d5a287395eb7b57e53058407e378019c3 100644 (file)
@@ -14,7 +14,6 @@
 #include "qemu-common.h"
 #include "hw/hw.h"
 #include "qemu-timer.h"
-#include "sysemu.h"
 #include "qemu-char.h"
 #include "buffered_file.h"
 
index 5a5827f6dbc3d7e81e2b0c6f1a987d53b515b252..6f75e2eb9f6442e2d46f4475060fbca7b1ba49fe 100755 (executable)
--- a/configure
+++ b/configure
@@ -175,6 +175,9 @@ trace_backend="nop"
 trace_file="trace"
 spice=""
 rbd=""
+smartcard=""
+smartcard_nss=""
+opengl=""
 
 # parse CC options first
 for opt do
@@ -281,7 +284,7 @@ else
 fi
 
 case "$cpu" in
-  alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64)
+  alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64|unicore32)
     cpu="$cpu"
   ;;
   i386|i486|i586|i686|i86pc|BePC)
@@ -492,6 +495,8 @@ for opt do
   case "$opt" in
   --help|-h) show_help=yes
   ;;
+  --version|-V) exec cat $source_path/VERSION
+  ;;
   --prefix=*) prefix="$optarg"
   ;;
   --interp-prefix=*) interp_prefix="$optarg"
@@ -718,12 +723,24 @@ for opt do
   ;;
   --enable-vhost-net) vhost_net="yes"
   ;;
+  --disable-opengl) opengl="no"
+  ;;
+  --enable-opengl) opengl="yes"
+  ;;
   --*dir)
   ;;
   --disable-rbd) rbd="no"
   ;;
   --enable-rbd) rbd="yes"
   ;;
+  --disable-smartcard) smartcard="no"
+  ;;
+  --enable-smartcard) smartcard="yes"
+  ;;
+  --disable-smartcard-nss) smartcard_nss="no"
+  ;;
+  --enable-smartcard-nss) smartcard_nss="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -798,6 +815,9 @@ case "$cpu" in
     hppa*)
            host_guest_base="yes"
            ;;
+    unicore32*)
+           host_guest_base="yes"
+           ;;
 esac
 
 [ -z "$guest_base" ] && guest_base="$host_guest_base"
@@ -921,6 +941,10 @@ echo "                           Default:trace-<pid>"
 echo "  --disable-spice          disable spice"
 echo "  --enable-spice           enable spice"
 echo "  --enable-rbd             enable building the rados block device (rbd)"
+echo "  --disable-smartcard      disable smartcard support"
+echo "  --enable-smartcard       enable smartcard support"
+echo "  --disable-smartcard-nss  disable smartcard nss support"
+echo "  --enable-smartcard-nss   enable smartcard nss support"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -1028,6 +1052,7 @@ sh4eb-linux-user \
 sparc-linux-user \
 sparc64-linux-user \
 sparc32plus-linux-user \
+unicore32-linux-user \
 "
     fi
 # the following are Darwin specific
@@ -1213,7 +1238,7 @@ else
   fi
   sdl=no
 fi
-if test -n "$cross_prefix" && test "`basename $sdlconfig`" = sdl-config; then
+if test -n "$cross_prefix" && test "$(basename "$sdlconfig")" = sdl-config; then
   echo warning: using "\"$sdlconfig\"" to detect cross-compiled sdl >&2
 fi
 
@@ -1921,15 +1946,36 @@ int main(void) { return 0; }
 EOF
   if compile_prog "" "$fdt_libs" ; then
     fdt=yes
-    libs_softmmu="$fdt_libs $libs_softmmu"
   else
     if test "$fdt" = "yes" ; then
       feature_not_found "fdt"
     fi
+    fdt_libs=
     fdt=no
   fi
 fi
 
+##########################################
+# opengl probe, used by milkymist-tmu2
+if test "$opengl" != "no" ; then
+  opengl_libs="-lGL"
+  cat > $TMPC << EOF
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+int main(void) { GL_VERSION; return 0; }
+EOF
+  if compile_prog "" "-lGL" ; then
+    opengl=yes
+  else
+    if test "$opengl" = "yes" ; then
+      feature_not_found "opengl"
+    fi
+    opengl_libs=
+    opengl=no
+  fi
+fi
+
 #
 # Check for xxxat() functions when we are building linux-user
 # emulator.  This is done because older glibc versions don't
@@ -2179,7 +2225,15 @@ cat > $TMPC << EOF
 
 int main(void)
 {
-    epoll_create1(0);
+    /* Note that we use epoll_create1 as a value, not as
+     * a function being called. This is necessary so that on
+     * old SPARC glibc versions where the function was present in
+     * the library but not declared in the header file we will
+     * fail the configure check. (Otherwise we will get a compiler
+     * warning but not an error, and will proceed to fail the
+     * qemu compile where we compile with -Werror.)
+     */
+    epoll_create1;
     return 0;
 }
 EOF
@@ -2304,6 +2358,31 @@ EOF
   fi
 fi
 
+# check for libcacard for smartcard support
+if test "$smartcard" != "no" ; then
+    smartcard="yes"
+    smartcard_cflags=""
+    # TODO - what's the minimal nss version we support?
+    if test "$smartcard_nss" != "no"; then
+        if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then
+            smartcard_nss="yes"
+            smartcard_cflags="-I\$(SRC_PATH)/libcacard"
+            libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
+            libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
+            QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags"
+            LIBS="$libcacard_libs $LIBS"
+        else
+            if test "$smartcard_nss" = "yes"; then
+                feature_not_found "nss"
+            fi
+            smartcard_nss="no"
+        fi
+    fi
+fi
+if test "$smartcard" = "no" ; then
+    smartcard_nss="no"
+fi
+
 ##########################################
 
 ##########################################
@@ -2461,7 +2540,9 @@ if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
         "$softmmu" = yes ; then
   roms="optionrom"
 fi
-
+if test "$cpu" = "ppc64" ; then
+  roms="$roms spapr-rtas"
+fi
 
 echo "Install prefix    $prefix"
 echo "BIOS directory    `eval echo $datadir`"
@@ -2540,6 +2621,8 @@ echo "Trace output file $trace_file-<pid>"
 echo "spice support     $spice"
 echo "rbd support       $rbd"
 echo "xfsctl support    $xfs"
+echo "nss used          $smartcard_nss"
+echo "OpenGL support    $opengl"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2563,7 +2646,7 @@ echo "docdir=$docdir" >> $config_host_mak
 echo "confdir=$confdir" >> $config_host_mak
 
 case "$cpu" in
-  i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64)
+  i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64|unicore32)
     ARCH=$cpu
   ;;
   armv4b|armv4l)
@@ -2822,6 +2905,18 @@ if test "$spice" = "yes" ; then
   echo "CONFIG_SPICE=y" >> $config_host_mak
 fi
 
+if test "$smartcard" = "yes" ; then
+  echo "CONFIG_SMARTCARD=y" >> $config_host_mak
+fi
+
+if test "$smartcard_nss" = "yes" ; then
+  echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
+fi
+
+if test "$opengl" = "yes" ; then
+  echo "CONFIG_OPENGL=y" >> $config_host_mak
+fi
+
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
   echo "CONFIG_BSD=y" >> $config_host_mak
@@ -2967,6 +3062,7 @@ mkdir -p $target_dir
 mkdir -p $target_dir/fpu
 mkdir -p $target_dir/tcg
 mkdir -p $target_dir/ide
+mkdir -p $target_dir/9pfs
 if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
   mkdir -p $target_dir/nwfpe
 fi
@@ -2984,6 +3080,7 @@ target_short_alignment=2
 target_int_alignment=4
 target_long_alignment=4
 target_llong_alignment=8
+target_libs_softmmu=
 
 TARGET_ARCH="$target_arch2"
 TARGET_BASE_ARCH=""
@@ -3017,6 +3114,7 @@ case "$target_arch2" in
   ;;
   lm32)
     target_phys_bits=32
+    target_libs_softmmu="$opengl_libs"
   ;;
   m68k)
     bflt="yes"
@@ -3031,6 +3129,7 @@ case "$target_arch2" in
     bflt="yes"
     target_nptl="yes"
     target_phys_bits=32
+    target_libs_softmmu="$fdt_libs"
   ;;
   mips|mipsel)
     TARGET_ARCH=mips
@@ -3055,6 +3154,7 @@ case "$target_arch2" in
     gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
     target_phys_bits=32
     target_nptl="yes"
+    target_libs_softmmu="$fdt_libs"
   ;;
   ppcemb)
     TARGET_BASE_ARCH=ppc
@@ -3062,6 +3162,7 @@ case "$target_arch2" in
     gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
     target_phys_bits=64
     target_nptl="yes"
+    target_libs_softmmu="$fdt_libs"
   ;;
   ppc64)
     TARGET_BASE_ARCH=ppc
@@ -3069,6 +3170,7 @@ case "$target_arch2" in
     gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
     target_phys_bits=64
     target_long_alignment=8
+    target_libs_softmmu="$fdt_libs"
   ;;
   ppc64abi32)
     TARGET_ARCH=ppc64
@@ -3077,6 +3179,7 @@ case "$target_arch2" in
     echo "TARGET_ABI32=y" >> $config_target_mak
     gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
     target_phys_bits=64
+    target_libs_softmmu="$fdt_libs"
   ;;
   sh4|sh4eb)
     TARGET_ARCH=sh4
@@ -3100,7 +3203,12 @@ case "$target_arch2" in
     target_phys_bits=64
   ;;
   s390x)
+    target_nptl="yes"
     target_phys_bits=64
+    target_long_alignment=8
+  ;;
+  unicore32)
+    target_phys_bits=32
   ;;
   *)
     echo "Unsupported target CPU"
@@ -3157,7 +3265,7 @@ fi
 if test "$target_softmmu" = "yes" ; then
   echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak
   echo "CONFIG_SOFTMMU=y" >> $config_target_mak
-  echo "LIBS+=$libs_softmmu" >> $config_target_mak
+  echo "LIBS+=$libs_softmmu $target_libs_softmmu" >> $config_target_mak
   echo "HWDIR=../libhw$target_phys_bits" >> $config_target_mak
   echo "subdir-$target: subdir-libhw$target_phys_bits" >> $config_host_mak
 fi
@@ -3170,6 +3278,11 @@ fi
 if test "$target_darwin_user" = "yes" ; then
   echo "CONFIG_DARWIN_USER=y" >> $config_target_mak
 fi
+if test "$smartcard_nss" = "yes" ; then
+  echo "subdir-$target: subdir-libcacard" >> $config_host_mak
+  echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
+  echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak
+fi
 list=""
 if test ! -z "$gdb_xml_files" ; then
   for x in $gdb_xml_files; do
@@ -3178,14 +3291,7 @@ if test ! -z "$gdb_xml_files" ; then
   echo "TARGET_XML_FILES=$list" >> $config_target_mak
 fi
 
-case "$target_arch2" in
-  i386|x86_64)
-    echo "CONFIG_NOSOFTFLOAT=y" >> $config_target_mak
-    ;;
-  *)
-    echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak
-    ;;
-esac
+echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak
 
 if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
   echo "TARGET_HAS_BFLT=y" >> $config_target_mak
@@ -3294,6 +3400,9 @@ if test "$target_softmmu" = "yes" ; then
   arm)
     cflags="-DHAS_AUDIO $cflags"
   ;;
+  lm32)
+    cflags="-DHAS_AUDIO $cflags"
+  ;;
   i386|mips|ppc)
     cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
   ;;
@@ -3354,7 +3463,7 @@ FILES="Makefile tests/Makefile"
 FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
 FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
-for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
+for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.rom $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
     FILES="$FILES pc-bios/`basename $bios_file`"
 done
 mkdir -p $DIRS
@@ -3380,9 +3489,17 @@ for hwlib in 32 64; do
   mkdir -p $d
   mkdir -p $d/ide
   symlink $source_path/Makefile.hw $d/Makefile
+  mkdir -p $d/9pfs
   echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak
 done
 
+if [ "$source_path" != `pwd` ]; then
+    # out of tree build
+    mkdir -p libcacard
+    rm -f libcacard/Makefile
+    ln -s "$source_path/libcacard/Makefile" libcacard/Makefile
+fi
+
 d=libuser
 mkdir -p $d
 symlink $source_path/Makefile.user $d/Makefile
index 4f4631d79c6684986e4686c7d4279f36fe2c51b5..88126ea6512328fd4f5a8c7ee51c83f8daa298d1 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -138,11 +138,20 @@ typedef union {
     uint64_t ll;
 } CPU_DoubleU;
 
-#ifdef TARGET_SPARC
+#if defined(FLOATX80)
+typedef union {
+     floatx80 d;
+     struct {
+         uint64_t lower;
+         uint16_t upper;
+     } l;
+} CPU_LDoubleU;
+#endif
+
+#if defined(CONFIG_SOFTFLOAT)
 typedef union {
     float128 q;
-#if defined(HOST_WORDS_BIGENDIAN) \
-    || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
+#if defined(HOST_WORDS_BIGENDIAN)
     struct {
         uint32_t upmost;
         uint32_t upper;
@@ -790,7 +799,19 @@ extern CPUState *cpu_single_env;
 #define CPU_INTERRUPT_SIPI   0x800 /* SIPI pending. */
 #define CPU_INTERRUPT_MCE    0x1000 /* (x86 only) MCE pending. */
 
-void cpu_interrupt(CPUState *s, int mask);
+#ifndef CONFIG_USER_ONLY
+typedef void (*CPUInterruptHandler)(CPUState *, int);
+
+extern CPUInterruptHandler cpu_interrupt_handler;
+
+static inline void cpu_interrupt(CPUState *s, int mask)
+{
+    cpu_interrupt_handler(s, mask);
+}
+#else /* USER_ONLY */
+void cpu_interrupt(CPUState *env, int mask);
+#endif /* USER_ONLY */
+
 void cpu_reset_interrupt(CPUState *env, int mask);
 
 void cpu_exit(CPUState *s);
index c239cc0def3d64cd30d6a1a16dbdcf3da4a84117..6410cccda5cc522d0b6bf134154fbbb37c033288 100644 (file)
@@ -79,14 +79,14 @@ void cpu_unregister_io_memory(int table_address);
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write);
 static inline void cpu_physical_memory_read(target_phys_addr_t addr,
-                                            uint8_t *buf, int len)
+                                            void *buf, int len)
 {
     cpu_physical_memory_rw(addr, buf, len, 0);
 }
 static inline void cpu_physical_memory_write(target_phys_addr_t addr,
-                                             const uint8_t *buf, int len)
+                                             const void *buf, int len)
 {
-    cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
+    cpu_physical_memory_rw(addr, (void *)buf, len, 1);
 }
 void *cpu_physical_memory_map(target_phys_addr_t addr,
                               target_phys_addr_t *plen,
index 5cc937904a3b7d4d2c017d27888a92ed4567e281..395cd8cf9047bc1eec16290ffbb638afe251a0ea 100644 (file)
@@ -267,6 +267,7 @@ int cpu_exec(CPUState *env1)
     env->cc_x = (env->sr >> 4) & 1;
 #elif defined(TARGET_ALPHA)
 #elif defined(TARGET_ARM)
+#elif defined(TARGET_UNICORE32)
 #elif defined(TARGET_PPC)
 #elif defined(TARGET_LM32)
 #elif defined(TARGET_MICROBLAZE)
@@ -335,6 +336,8 @@ int cpu_exec(CPUState *env1)
                     do_interrupt(env);
 #elif defined(TARGET_ARM)
                     do_interrupt(env);
+#elif defined(TARGET_UNICORE32)
+                    do_interrupt(env);
 #elif defined(TARGET_SH4)
                    do_interrupt(env);
 #elif defined(TARGET_ALPHA)
@@ -343,6 +346,8 @@ int cpu_exec(CPUState *env1)
                     do_interrupt(env);
 #elif defined(TARGET_M68K)
                     do_interrupt(0);
+#elif defined(TARGET_S390X)
+                    do_interrupt(env);
 #endif
                     env->exception_index = -1;
 #endif
@@ -367,7 +372,7 @@ int cpu_exec(CPUState *env1)
                     }
 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
     defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
-    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32)
+    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
                     if (interrupt_request & CPU_INTERRUPT_HALT) {
                         env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                         env->halted = 1;
@@ -514,6 +519,12 @@ int cpu_exec(CPUState *env1)
                         do_interrupt(env);
                         next_tb = 0;
                     }
+#elif defined(TARGET_UNICORE32)
+                    if (interrupt_request & CPU_INTERRUPT_HARD
+                        && !(env->uncached_asr & ASR_I)) {
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #elif defined(TARGET_SH4)
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
                         do_interrupt(env);
@@ -551,6 +562,12 @@ int cpu_exec(CPUState *env1)
                         do_interrupt(1);
                         next_tb = 0;
                     }
+#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+                        (env->psw.mask & PSW_MASK_EXT)) {
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #endif
                    /* Don't use the cached interupt_request value,
                       do_interrupt may have updated the EXITTB flag. */
@@ -664,6 +681,7 @@ int cpu_exec(CPUState *env1)
     env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
 #elif defined(TARGET_ARM)
     /* XXX: Save/restore host fpu exception state?.  */
+#elif defined(TARGET_UNICORE32)
 #elif defined(TARGET_SPARC)
 #elif defined(TARGET_PPC)
 #elif defined(TARGET_LM32)
@@ -790,7 +808,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
     if (tb) {
         /* the PC is inside the translated code. It means that we have
            a virtual CPU fault */
-        cpu_restore_state(tb, env, pc, puc);
+        cpu_restore_state(tb, env, pc);
     }
 
     /* we restore the process signal mask as the sigreturn should
diff --git a/cpus.c b/cpus.c
index 41bec7cc561df67465b7c22c6eef90e5fd9233f9..1fc34b75c2a3674be317d4ef5d14a5d6e5892bdd 100644 (file)
--- a/cpus.c
+++ b/cpus.c
@@ -155,7 +155,7 @@ static bool cpu_thread_is_idle(CPUState *env)
     return true;
 }
 
-static bool all_cpu_threads_idle(void)
+bool all_cpu_threads_idle(void)
 {
     CPUState *env;
 
@@ -739,6 +739,9 @@ static void qemu_tcg_wait_io_event(void)
     CPUState *env;
 
     while (all_cpu_threads_idle()) {
+       /* Start accounting real time to the virtual clock if the CPUs
+          are idle.  */
+        qemu_clock_warp(vm_clock);
         qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
     }
 
@@ -830,6 +833,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
 
     while (1) {
         cpu_exec_all();
+        if (use_icount && qemu_next_icount_deadline() <= 0) {
+            qemu_notify_event();
+        }
         qemu_tcg_wait_io_event();
     }
 
@@ -1044,7 +1050,7 @@ static int tcg_cpu_exec(CPUState *env)
         qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
         env->icount_decr.u16.low = 0;
         env->icount_extra = 0;
-        count = qemu_icount_round (qemu_next_deadline());
+        count = qemu_icount_round(qemu_next_icount_deadline());
         qemu_icount += count;
         decr = (count > 0xffff) ? 0xffff : count;
         count -= decr;
@@ -1070,6 +1076,9 @@ bool cpu_exec_all(void)
 {
     int r;
 
+    /* Account partial waits to the vm_clock.  */
+    qemu_clock_warp(vm_clock);
+
     if (next_cpu == NULL) {
         next_cpu = first_cpu;
     }
diff --git a/cpus.h b/cpus.h
index e0211260c3cb8323f0f4d422ed281e127fc33697..6fdeb0d8f2e8a75b767094fb84eb83930761b10b 100644 (file)
--- a/cpus.h
+++ b/cpus.h
@@ -8,6 +8,10 @@ void resume_all_vcpus(void);
 void pause_all_vcpus(void);
 void cpu_stop_current(void);
 
+void cpu_synchronize_all_states(void);
+void cpu_synchronize_all_post_reset(void);
+void cpu_synchronize_all_post_init(void);
+
 /* vl.c */
 extern int smp_cores;
 extern int smp_threads;
index f6aa71e058d4b78b04a2ff046d609382482b0f10..cc29bddd95d25217e9fb4f2f6d5e64aa3f1ef073 100644 (file)
@@ -211,7 +211,7 @@ void do_compare_and_swap32(void *cpu_env, int num)
     uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
     DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
 
-    if(value && old == tswap32(*value))
+    if(old == tswap32(*value))
     {
         uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
         *value = tswap32(new);
index ab774a2509b739309359ea595941f47e9f2fd390..0d19974b40b290878201e612e54147b9e3c9f4e8 100644 (file)
@@ -1,4 +1,6 @@
 # Default configuration for lm32-softmmu
 
 CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
+CONFIG_SD=y
diff --git a/default-configs/unicore32-linux-user.mak b/default-configs/unicore32-linux-user.mak
new file mode 100644 (file)
index 0000000..6aafd21
--- /dev/null
@@ -0,0 +1 @@
+# Default configuration for unicore32-linux-user
index 426a63155cf3fa7706367bcd9ed540d0aac8d8f1..f5d5eb1bca5ecdd5cba9c34935d8901a2d627e1a 100644 (file)
@@ -20,7 +20,6 @@
 
 #include "config.h"
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "device_tree.h"
 #include "hw/loader.h"
 
@@ -74,7 +73,7 @@ fail:
 }
 
 int qemu_devtree_setprop(void *fdt, const char *node_path,
-                         const char *property, uint32_t *val_array, int size)
+                         const char *property, void *val_array, int size)
 {
     int offset;
 
index f05c4e7311375a443e2802e6c56ee7845ac7bc72..cecd98f0422ff2483ab823a0e1272051df6d2b5d 100644 (file)
@@ -17,7 +17,7 @@
 void *load_device_tree(const char *filename_path, int *sizep);
 
 int qemu_devtree_setprop(void *fdt, const char *node_path,
-                         const char *property, uint32_t *val_array, int size);
+                         const char *property, void *val_array, int size);
 int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
                               const char *property, uint32_t val);
 int qemu_devtree_setprop_string(void *fdt, const char *node_path,
diff --git a/disas.c b/disas.c
index c76f36f590a1e77fe82b2184b1f6d5db718b9b64..223606cc50293f09af73659711bad3397e6a094f 100644 (file)
--- a/disas.c
+++ b/disas.c
@@ -215,6 +215,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
         disasm_info.mach = bfd_mach_cris_v32;
         print_insn = print_insn_crisv32;
     }
+#elif defined(TARGET_S390X)
+    disasm_info.mach = bfd_mach_s390_64;
+    print_insn = print_insn_s390;
 #elif defined(TARGET_MICROBLAZE)
     disasm_info.mach = bfd_arch_microblaze;
     print_insn = print_insn_microblaze;
@@ -342,7 +345,7 @@ monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                      struct disassemble_info *info)
 {
     if (monitor_disas_is_physical) {
-        cpu_physical_memory_rw(memaddr, myaddr, length, 0);
+        cpu_physical_memory_read(memaddr, myaddr, length);
     } else {
         cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
     }
@@ -414,6 +417,9 @@ void monitor_disas(Monitor *mon, CPUState *env,
 #elif defined(TARGET_SH4)
     disasm_info.mach = bfd_mach_sh4;
     print_insn = print_insn_sh;
+#elif defined(TARGET_S390X)
+    disasm_info.mach = bfd_mach_s390_64;
+    print_insn = print_insn_s390;
 #else
     monitor_printf(mon, "0x" TARGET_FMT_lx
                    ": Asm output not supported on this arch\n", pc);
diff --git a/docs/ccid.txt b/docs/ccid.txt
new file mode 100644 (file)
index 0000000..b8e504a
--- /dev/null
@@ -0,0 +1,135 @@
+Qemu CCID Device Documentation.
+
+Contents
+1. USB CCID device
+2. Building
+3. Using ccid-card-emulated with hardware
+4. Using ccid-card-emulated with certificates
+5. Using ccid-card-passthru with client side hardware
+6. Using ccid-card-passthru with client side certificates
+7. Passthrough protocol scenario
+8. libcacard
+
+1. USB CCID device
+
+The USB CCID device is a USB device implementing the CCID specification, which
+lets one connect smart card readers that implement the same spec. For more
+information see the specification:
+
+ Universal Serial Bus
+ Device Class: Smart Card
+ CCID
+ Specification for
+ Integrated Circuit(s) Cards Interface Devices
+ Revision 1.1
+ April 22rd, 2005
+
+Smartcard are used for authentication, single sign on, decryption in
+public/private schemes and digital signatures. A smartcard reader on the client
+cannot be used on a guest with simple usb passthrough since it will then not be
+available on the client, possibly locking the computer when it is "removed". On
+the other hand this device can let you use the smartcard on both the client and
+the guest machine. It is also possible to have a completely virtual smart card
+reader and smart card (i.e. not backed by a physical device) using this device.
+
+2. Building
+
+The cryptographic functions and access to the physical card is done via NSS.
+
+Installing NSS:
+
+In redhat/fedora:
+    yum install nss-devel
+In ubuntu/debian:
+    apt-get install libnss3-dev
+    (not tested on ubuntu)
+
+Configuring and building:
+    ./configure --enable-smartcard && make
+
+3. Using ccid-card-emulated with hardware
+
+Assuming you have a working smartcard on the host with the current
+user, using NSS, qemu acts as another NSS client using ccid-card-emulated:
+
+    qemu -usb -device usb-ccid -device ccid-card-emualated
+
+4. Using ccid-card-emulated with certificates
+
+You must create the certificates. This is a one time process. We use NSS
+certificates:
+
+    certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=cert1" -n cert1
+
+Note: you must have exactly three certificates.
+
+Assuming the current user can access the certificates (use certutil -L to
+verify), you can use the emulated card type with the certificates backend:
+
+    qemu -usb -device usb-ccid -device ccid-card-emulated,backend=certificates,cert1=cert1,cert2=cert2,cert3=cert3
+
+5. Using ccid-card-passthru with client side hardware
+
+on the host specify the ccid-card-passthru device with a suitable chardev:
+
+    qemu -chardev socket,server,host=0.0.0.0,port=2001,id=ccid,nowait -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid
+
+on the client run vscclient, built when you built the libcacard library:
+    libcacard/vscclient <qemu-host> 2001
+
+6. Using ccid-card-passthru with client side certificates
+
+Run qemu as per #5, and run vscclient as follows:
+(Note: vscclient command line interface is in a state of change)
+
+    libcacard/vscclient -e "db=\"/etc/pki/nssdb\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)" <qemu-host> 2001
+
+7. Passthrough protocol scenario
+
+This is a typical interchange of messages when using the passthru card device.
+usb-ccid is a usb device. It defaults to an unattached usb device on startup.
+usb-ccid expects a chardev and expects the protocol defined in
+cac_card/vscard_common.h to be passed over that.
+The usb-ccid device can be in one of three modes:
+ * detached
+ * attached with no card
+ * attached with card
+
+A typical interchange is: (the arrow shows who started each exchange, it can be client
+originated or guest originated)
+
+client event      |      vscclient           |    passthru    |     usb-ccid  |  guest event
+----------------------------------------------------------------------------------------------
+                  |      VSC_Init            |                |               |
+                  |      VSC_ReaderAdd       |                |     attach    |
+                  |                          |                |               |  sees new usb device.
+card inserted ->  |                          |                |               |
+                  |      VSC_ATR             |   insert       |     insert    |  see new card
+                  |                          |                |               |
+                  |      VSC_APDU            |   VSC_APDU     |               | <- guest sends APDU
+client<->physical |                          |                |               |
+card APDU exchange|                          |                |               |
+client response ->|      VSC_APDU            |   VSC_APDU     |               |  receive APDU response
+                                                    ...
+                                    [APDU<->APDU repeats several times]
+                                                    ...
+card removed  ->  |                          |                |               |
+                  |      VSC_CardRemove      |   remove       |    remove     |   card removed
+                                                    ...
+                                    [(card insert, apdu's, card remove) repeat]
+                                                    ...
+kill/quit         |                          |                |               |
+  vscclient       |                          |                |               |
+                  |      VSC_ReaderRemove    |                |    detach     |
+                  |                          |                |               |   usb device removed.
+
+
+8. libcacard
+
+ccid-card-passthru and vscclient use libcacard as the card emulator.
+libcacard implements a completely virtual CAC (DoD standard for smart cards)
+compliant card and uses NSS to actually retrive certificates and do any
+encryption using the backend (real reader + card or file backed certificates).
+
+For documentation of cac_card see README in libcacard subdirectory.
+
diff --git a/docs/libcacard.txt b/docs/libcacard.txt
new file mode 100644 (file)
index 0000000..5dee6fa
--- /dev/null
@@ -0,0 +1,483 @@
+This file documents the CAC (Common Access Card) library in the libcacard
+subdirectory.
+
+Virtual Smart Card Emulator
+
+This emulator is designed to provide emulation of actual smart cards to a
+virtual card reader running in a guest virtual machine. The emulated smart
+cards can be representations of real smart cards, where the necessary functions
+such as signing, card removal/insertion, etc. are mapped to real, physical
+cards which are shared with the client machine the emulator is running on, or
+the cards could be pure software constructs.
+
+The emulator is structured to allow multiple replacable or additional pieces,
+so it can be easily modified for future requirements. The primary envisioned
+modifications are:
+
+1) The socket connection to the virtual card reader (presumably a CCID reader,
+but other ISO-7816 compatible readers could be used). The code that handles
+this is in vscclient.c.
+
+2) The virtual card low level emulation. This is currently supplied by using
+NSS. This emulation could be replaced by implementations based on other
+security libraries, including but not limitted to openssl+pkcs#11 library,
+raw pkcs#11, Microsoft CAPI, direct opensc calls, etc. The code that handles
+this is in vcard_emul_nss.c.
+
+3) Emulation for new types of cards. The current implementation emulates the
+original DoD CAC standard with separate pki containers. This emulator lives in
+cac.c. More than one card type emulator could be included. Other cards could
+be emulated as well, including PIV, newer versions of CAC, PKCS #15, etc.
+
+--------------------
+Replacing the Socket Based Virtual Reader Interface.
+
+The current implementation contains a replacable module vscclient.c. The
+current vscclient.c implements a sockets interface to the virtual ccid reader
+on the guest. CCID commands that are pertinent to emulation are passed
+across the socket, and their responses are passed back along that same socket.
+The protocol that vscclient uses is defined in vscard_common.h and connects
+to a qemu ccid usb device. Since this socket runs as a client, vscclient.c
+implements a program with a main entry. It also handles argument parsing for
+the emulator.
+
+An application that wants to use the virtual reader can replace vscclient.c
+with it's own implementation that connects to it's own CCID reader.  The calls
+that the CCID reader can call are:
+
+      VReaderList * vreader_get_reader_list();
+
+  This function returns a list of virtual readers.  These readers may map to
+  physical devices, or simulated devices depending on vcard the back end. Each
+  reader in the list should represent a reader to the virtual machine. Virtual
+  USB address mapping is left to the CCID reader front end. This call can be
+  made any time to get an updated list. The returned list is a copy of the
+  internal list that can be referenced by the caller without locking. This copy
+  must be freed by the caller with vreader_list_delete when it is no longer
+  needed.
+
+      VReaderListEntry *vreader_list_get_first(VReaderList *);
+
+  This function gets the first entry on the reader list. Along with
+  vreader_list_get_next(), vreader_list_get_first() can be used to walk the
+  reader list returned from vreader_get_reader_list(). VReaderListEntries are
+  part of the list themselves and do not need to be freed separately from the
+  list. If there are no entries on the list, it will return NULL.
+
+      VReaderListEntry *vreader_list_get_next(VReaderListEntry *);
+
+  This function gets the next entry in the list. If there are no more entries
+  it will return NULL.
+
+      VReader * vreader_list_get_reader(VReaderListEntry *)
+
+  This function returns the reader stored in the reader List entry. Caller gets
+  a new reference to a reader. The caller must free it's reference when it is
+  finished with vreader_free().
+
+      void vreader_free(VReader *reader);
+
+   This function frees a reference to a reader. Reader's are reference counted
+   and are automatically deleted when the last reference is freed.
+
+      void vreader_list_delete(VReaderList *list);
+
+   This function frees the list, all the elements on the list, and all the
+   reader references held by the list.
+
+      VReaderStatus vreader_power_on(VReader *reader, char *atr, int *len);
+
+  This functions simulates a card power on. Virtual cards do not care about
+  the actual voltage and other physical parameters, but it does care that the
+  card is actually on or off. Cycling the card causes the card to reset. If
+  the caller provides enough space, vreader_power_on will return the ATR of
+  the virtual card. The amount of space provided in atr should be indicated
+  in *len. The function modifies *len to be the actual length of of the
+  returned ATR.
+
+      VReaderStatus vreader_power_off(VReader *reader);
+
+  This function simulates a power off of a virtual card.
+
+      VReaderStatus vreader_xfer_bytes(VReader *reader, unsigne char *send_buf,
+                                       int send_buf_len,
+                                       unsigned char *receive_buf,
+                                       int receive_buf_len);
+
+  This functions send a raw apdu to a card and returns the card's response.
+  The CCID front end should return the response back. Most of the emulation
+  is driven from these APDUs.
+
+      VReaderStatus vreader_card_is_present(VReader *reader);
+
+  This function returns whether or not the reader has a card inserted. The
+  vreader_power_on, vreader_power_off, and vreader_xfer_bytes will return
+  VREADER_NO_CARD.
+
+       const char *vreader_get_name(VReader *reader);
+
+  This function returns the name of the reader. The name comes from the card
+  emulator level and is usually related to the name of the physical reader.
+
+       VReaderID vreader_get_id(VReader *reader);
+
+  This function returns the id of a reader. All readers start out with an id
+  of -1. The application can set the id with vreader_set_id.
+
+       VReaderStatus vreader_get_id(VReader *reader, VReaderID id);
+
+  This function sets the reader id. The application is responsible for making
+  sure that the id is unique for all readers it is actively using.
+
+       VReader *vreader_find_reader_by_id(VReaderID id);
+
+  This function returns the reader which matches the id. If two readers match,
+  only one is returned. The function returns NULL if the id is -1.
+
+       Event *vevent_wait_next_vevent();
+
+  This function blocks waiting for reader and card insertion events. There
+  will be one event for each card insertion, each card removal, each reader
+  insertion and each reader removal. At start up, events are created for all
+  the initial readers found, as well as all the cards that are inserted.
+
+       Event *vevent_get_next_vevent();
+
+  This function returns a pending event if it exists, otherwise it returns
+  NULL. It does not block.
+
+----------------
+Card Type Emulator: Adding a New Virtual Card Type
+
+The ISO 7816 card spec describes 2 types of cards:
+ 1) File system cards, where the smartcard is managed by reading and writing
+data to files in a file system. There is currently only boiler plate
+implemented for file system cards.
+ 2) VM cards, where the card has loadable applets which perform the card
+functions. The current implementation supports VM cards.
+
+In the case of VM cards, the difference between various types of cards is
+really what applets have been installed in that card. This structure is
+mirrored in card type emulators. The 7816 emulator already handles the basic
+ISO 7186 commands. Card type emulators simply need to add the virtual applets
+which emulate the real card applets. Card type emulators have exactly one
+public entry point:
+
+       VCARDStatus xxx_card_init(VCard *card, const char *flags,
+                               const unsigned char *cert[],
+                               int cert_len[],
+                               VCardKey *key[],
+                               int cert_count);
+
+  The parameters for this are:
+  card       - the virtual card structure which will prepresent this card.
+  flags      - option flags that may be specific to this card type.
+  cert       - array of binary certificates.
+  cert_len   - array of lengths of each of the certificates specified in cert.
+  key        - array of opaque key structures representing the private keys on
+               the card.
+  cert_count - number of entries in cert, cert_len, and key arrays.
+
+  Any cert, cert_len, or key with the same index are matching sets. That is
+  cert[0] is cert_len[0] long and has the corresponsing private key of key[0].
+
+The card type emulator is expected to own the VCardKeys, but it should copy
+any raw cert data it wants to save. It can create new applets and add them to
+the card using the following functions:
+
+       VCardApplet *vcard_new_applet(VCardProcessAPDU apdu_func,
+                                     VCardResetApplet reset_func,
+                                     const unsigned char *aid,
+                                     int aid_len);
+
+  This function creates a new applet. Applet structures store the following
+  information:
+     1) the AID of the applet (set by aid and aid_len).
+     2) a function to handle APDUs for this applet. (set by apdu_func, more on
+        this below).
+     3) a function to reset the applet state when the applet is selected.
+        (set by reset_func, more on this below).
+     3) applet private data, a data pointer used by the card type emulator to
+        store any data or state it needs to complete requests. (set by a
+        separate call).
+     4) applet private data free, a function used to free the applet private
+        data when the applet itself is destroyed.
+  The created applet can be added to the card with vcard_add_applet below.
+
+        void vcard_set_applet_private(VCardApplet *applet,
+                                      VCardAppletPrivate *private,
+                                      VCardAppletPrivateFree private_free);
+  This function sets the private data and the corresponding free function.
+  VCardAppletPrivate is an opaque data structure to the rest of the emulator.
+  The card type emulator can define it any way it wants by defining
+  struct VCardAppletPrivateStruct {};. If there is already a private data
+  structure on the applet, the old one is freed before the new one is set up.
+  passing two NULL clear any existing private data.
+
+         VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet);
+
+  Add an applet onto the list of applets attached to the card. Once an applet
+  has been added, it can be selected by it's aid, and then commands will be
+  routed to it VCardProcessAPDU function. This function adopts the applet the
+  passed int applet. Note: 2 applets with the same AID should not be added to
+  the same card. It's permissible to add more than one applet. Multiple applets
+  may have the same VCardPRocessAPDU entry point.
+
+The certs and keys should be attached to private data associated with one or
+more appropriate applets for that card. Control will come to the card type
+emulators once one of its applets are selected through the VCardProcessAPDU
+function it specified when it created the applet.
+
+The signature of VCardResetApplet is:
+        VCardStatus (*VCardResetApplet) (VCard *card, int channel);
+  This function will reset the any internal applet state that needs to be
+  cleared after a select applet call. It should return VCARD_DONE;
+
+The signature of VCardProcessAPDU is:
+        VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu,
+                                         VCardResponse **response);
+  This function examines the APDU and determines whether it should process
+  the apdu directly, reject the apdu as invalid, or pass the apdu on to
+  the basic 7816 emulator for processing.
+      If the 7816 emulator should process the apdu, then the VCardProcessAPDU
+  should return VCARD_NEXT.
+      If there is an error, then VCardProcessAPDU should return an error
+  response using vcard_make_response and the appropriate 7816 error code
+  (see card_7816t.h) or vcard_make_response with a card type specific error
+  code. It should then return VCARD_DONE.
+      If the apdu can be processed correctly, VCardProcessAPDU should do so,
+  set the response value appropriately for that APDU, and return VCARD_DONE.
+  VCardProcessAPDU should always set the response if it returns VCARD_DONE.
+  It should always either return VCARD_DONE or VCARD_NEXT.
+
+Parsing the APDU --
+
+Prior to processing calling the card type emulator's VCardProcessAPDU function, the emulator has already decoded the APDU header and set several fields:
+
+   apdu->a_data - The raw apdu data bytes.
+   apdu->a_len  - The len of the raw apdu data.
+   apdu->a_body - The start of any post header parameter data.
+   apdu->a_Lc   - The parameter length value.
+   apdu->a_Le   - The expected length of any returned data.
+   apdu->a_cla  - The raw apdu class.
+   apdu->a_channel - The channel (decoded from the class).
+   apdu->a_secure_messaging_type - The decoded secure messagin type
+                                   (from class).
+   apdu->a_type - The decode class type.
+   apdu->a_gen_type - the generic class type (7816, PROPRIETARY, RFU, PTS).
+   apdu->a_ins  - The instruction byte.
+   apdu->a_p1   - Parameter 1.
+   apdu->a_p2   - Parameter 2.
+
+Creating a Response --
+
+The expected result of any APDU call is a response. The card type emulator must
+set *response with an appropriate VCardResponse value if it returns VCARD_DONE.
+Reponses could be as simple as returning a 2 byte status word response, to as
+complex as returning a block of data along with a 2 byte response. Which is
+returned will depend on the semantics of the APDU. The following functions will
+create card responses.
+
+        VCardResponse *vcard_make_response(VCard7816Status status);
+
+    This is the most basic function to get a response. This function will
+    return a response the consists soley one 2 byte status code. If that status
+    code is defined in card_7816t.h, then this function is guarrenteed to
+    return a response with that status. If a cart type specific status code
+    is passed and vcard_make_response fails to allocate the appropriate memory
+    for that response, then vcard_make_response will return a VCardResponse
+    of VCARD7816_STATUS_EXC_ERROR_MEMORY. In any case, this function is
+    guarrenteed to return a valid VCardResponse.
+
+        VCardResponse *vcard_response_new(unsigned char *buf, int len,
+                                          VCard7816Status status);
+
+    This function is similar to vcard_make_response except it includes some
+    returned data with the response. It could also fail to allocate enough
+    memory, in which case it will return NULL.
+
+        VCardResponse *vcard_response_new_status_bytes(unsigned char sw1,
+                                                       unsigned char sw2);
+
+    Sometimes in 7816 the response bytes are treated as two separate bytes with
+    split meanings. This function allows you to create a response based on
+    two separate bytes. This function could fail, in which case it will return
+    NULL.
+
+       VCardResponse *vcard_response_new_bytes(unsigned char *buf, int len,
+                                               unsigned char sw1,
+                                               unsigned char sw2);
+
+    This function is the same as vcard_response_new except you may specify
+    the status as two separate bytes like vcard_response_new_status_bytes.
+
+
+Implementing functionality ---
+
+The following helper functions access information about the current card
+and applet.
+
+        VCARDAppletPrivate *vcard_get_current_applet_private(VCard *card,
+                                                             int channel);
+
+    This function returns any private data set by the card type emulator on
+    the currently selected applet. The card type emulator keeps track of the
+    current applet state in this data structure. Any certs and keys associated
+    with a particular applet is also stored here.
+
+        int vcard_emul_get_login_count(VCard *card);
+
+    This function returns the the number of remaing login attempts for this
+    card. If the card emulator does not know, or the card does not have a
+    way of giving this information, this function returns -1.
+
+
+         VCard7816Status vcard_emul_login(VCard *card, unsigned char *pin,
+                                          int pin_len);
+
+    This function logins into the card and return the standard 7816 status
+    word depending on the success or failure of the call.
+
+         void vcard_emul_delete_key(VCardKey *key);
+
+     This function frees the VCardKey passed in to xxxx_card_init. The card
+     type emulator is responsible for freeing this key when it no longer needs
+     it.
+
+         VCard7816Status vcard_emul_rsa_op(VCard *card, VCardKey *key,
+                                           unsigned char *buffer,
+                                           int buffer_size);
+
+     This function does a raw rsa op on the buffer with the given key.
+
+The sample card type emulator is found in cac.c. It implements the cac specific
+applets.  Only those applets needed by the coolkey pkcs#11 driver on the guest
+have been implemented. To support the full range CAC middleware, a complete CAC
+card according to the CAC specs should be implemented here.
+
+------------------------------
+Virtual Card Emulator
+
+This code accesses both real smart cards and simulated smart cards through
+services provided on the client. The current implementation uses NSS, which
+already knows how to talk to various PKCS #11 modules on the client, and is
+portable to most operating systems. A particular emulator can have only one
+virtual card implementation at a time.
+
+The virtual card emulator consists of a series of virtual card services. In
+addition to the services describe above (services starting with
+vcard_emul_xxxx), the virtual card emulator also provides the following
+functions:
+
+    VCardEmulError vcard_emul_init(cont VCardEmulOptions *options);
+
+  The options structure is built by another function in the virtual card
+  interface where a string of virtual card emulator specific strings are
+  mapped to the options. The actual structure is defined by the virutal card
+  emulator and is used to determine the configuration of soft cards, or to
+  determine which physical cards to present to the guest.
+
+  The vcard_emul_init function will build up sets of readers, create any
+  threads that are needed to watch for changes in the reader state. If readers
+  have cards present in them, they are also initialized.
+
+  Readers are created with the function.
+
+          VReader *vreader_new(VReaderEmul *reader_emul,
+                               VReaderEmulFree reader_emul_free);
+
+      The freeFunc is used to free the VReaderEmul * when the reader is
+      destroyed.  The VReaderEmul structure is an opaque structure to the
+      rest of the code, but defined by the virtual card emulator, which can
+      use it to store any reader specific state.
+
+  Once the reader has been created, it can be added to the front end with the
+  call:
+
+           VReaderStatus vreader_add_reader(VReader *reader);
+
+      This function will automatically generate the appropriate new reader
+      events and add the reader to the list.
+
+  To create a new card, the virtual card emulator will call a similiar
+  function.
+
+           VCard *vcard_new(VCardEmul *card_emul,
+                            VCardEmulFree card_emul_free);
+
+      Like vreader_new, this function takes a virtual card emulator specific
+      structure which it uses to keep track of the card state.
+
+  Once the card is created, it is attached to a card type emulator with the
+  following function:
+
+            VCardStatus vcard_init(VCard *vcard, VCardEmulType type,
+                                   const char *flags,
+                                   unsigned char *const *certs,
+                                   int *cert_len,
+                                   VCardKey *key[],
+                                   int cert_count);
+
+      The vcard is the value returned from vcard_new. The type is the
+      card type emulator that this card should presented to the guest as.
+      The flags are card type emulator specific options. The certs,
+      cert_len, and keys are all arrays of length cert_count. These are the
+      the same of the parameters xxxx_card_init() accepts.
+
+   Finally the card is associated with it's reader by the call:
+
+            VReaderStatus vreader_insert_card(VReader *vreader, VCard *vcard);
+
+      This function, like vreader_add_reader, will take care of any event
+      notification for the card insert.
+
+
+    VCardEmulError vcard_emul_force_card_remove(VReader *vreader);
+
+  Force a card that is present to appear to be removed to the guest, even if
+  that card is a physical card and is present.
+
+
+    VCardEmulError vcard_emul_force_card_insert(VReader *reader);
+
+  Force a card that has been removed by vcard_emul_force_card_remove to be
+  reinserted from the point of view of the guest. This will only work if the
+  card is physically present (which is always true fro a soft card).
+
+     void vcard_emul_get_atr(Vcard *card, unsigned char *atr, int *atr_len);
+
+  Return the virtual ATR for the card. By convention this should be the value
+  VCARD_ATR_PREFIX(size) followed by several ascii bytes related to this
+  particular emulator. For instance the NSS emulator returns
+  {VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }. Do ot return more data then *atr_len;
+
+     void vcard_emul_reset(VCard *card, VCardPower power)
+
+   Set the state of 'card' to the current power level and reset its internal
+   state (logout, etc).
+
+-------------------------------------------------------
+List of files and their function:
+README - This file
+card_7816.c - emulate basic 7816 functionality. Parse APDUs.
+card_7816.h - apdu and response services definitions.
+card_7816t.h - 7816 specific structures, types and definitions.
+event.c - event handling code.
+event.h - event handling services definitions.
+eventt.h - event handling structures and types
+vcard.c - handle common virtual card services like creation, destruction, and
+          applet management.
+vcard.h - common virtual card services function definitions.
+vcardt.h - comon virtual card types
+vreader.c - common virtual reader services.
+vreader.h - common virtual reader services definitions.
+vreadert.h - comon virtual reader types.
+vcard_emul_type.c - manage the card type emulators.
+vcard_emul_type.h - definitions for card type emulators.
+cac.c - card type emulator for CAC cards
+vcard_emul.h - virtual card emulator service definitions.
+vcard_emul_nss.c - virtual card emulator implementation for nss.
+vscclient.c - socket connection to guest qemu usb driver.
+vscard_common.h - common header with the guest qemu usb driver.
+mutex.h - header file for machine independent mutexes.
+link_test.c - static test to make sure all the symbols are properly defined.
index 1d5fa87e014a6954dbeca56638418f31918ffa2e..7982e058b2c753dc6ee01b8ecb66502c377652f1 100644 (file)
@@ -89,6 +89,7 @@ L1, L2, and data cluster offsets must be aligned to header.cluster_size.  The fo
 
 ===Data cluster offsets===
 * 0 - unallocated.  The data cluster is not yet allocated.
+* 1 - zero.  The data cluster contents are all zeroes and no cluster is allocated.
 
 Future format extensions may wish to store per-offset information.  The least significant 12 bits of an offset are reserved for this purpose and must be set to zero.  Image files with cluster_size > 2^12 will have more unused bits which should also be zeroed.
 
@@ -97,6 +98,13 @@ Reads to an unallocated area of the image file access the backing file.  If ther
 
 Writes to an unallocated area cause a new data clusters to be allocated, and a new L2 table if that is also unallocated.  The new data cluster is populated with data from the backing file (or zeroes if no backing file) and the data being written.
 
+===Zero data clusters===
+Zero data clusters are a space-efficient way of storing zeroed regions of the image.
+
+Reads to a zero data cluster produce zeroes.  Note that the difference between an unallocated and a zero data cluster is that zero data clusters stop the reading of contents from the backing file.
+
+Writes to a zero data cluster cause a new data cluster to be allocated.  The new data cluster is populated with zeroes and the data being written.
+
 ===Logical offset translation===
 Logical offsets are translated into cluster offsets as follows:
 
index f15069c96b8972d0ccd3d49ebfe6fca63124710a..c99a0f27cfa79a79d8de558da3dbaab6cf84e7f8 100644 (file)
@@ -26,14 +26,14 @@ for debugging, profiling, and observing execution.
 
 == Trace events ==
 
-There is a set of static trace events declared in the trace-events source
+There is a set of static trace events declared in the "trace-events" source
 file.  Each trace event declaration names the event, its arguments, and the
 format string which can be used for pretty-printing:
 
     qemu_malloc(size_t size, void *ptr) "size %zu ptr %p"
     qemu_free(void *ptr) "ptr %p"
 
-The trace-events file is processed by the tracetool script during build to
+The "trace-events" file is processed by the "tracetool" script during build to
 generate code for the trace events.  Trace events are invoked directly from
 source code like this:
 
@@ -52,10 +52,10 @@ source code like this:
 
 === Declaring trace events ===
 
-The tracetool script produces the trace.h header file which is included by
+The "tracetool" script produces the trace.h header file which is included by
 every source file that uses trace events.  Since many source files include
-trace.h, it uses a minimum of types and other header files included to keep
-the namespace clean and compile times and dependencies down.
+trace.h, it uses a minimum of types and other header files included to keep the
+namespace clean and compile times and dependencies down.
 
 Trace events should use types as follows:
 
@@ -69,6 +69,11 @@ Trace events should use types as follows:
    cannot include all user-defined struct declarations and it is therefore
    necessary to use void * for pointers to structs.
 
+   Pointers (including char *) cannot be dereferenced easily (or at all) in
+   some trace backends.  If pointers are used, ensure they are meaningful by
+   themselves and do not assume the data they point to will be traced.  Do
+   not pass in string arguments.
+
  * For everything else, use primitive scalar types (char, int, long) with the
    appropriate signedness.
 
@@ -105,10 +110,10 @@ portability macros, ensure they are preceded and followed by double quotes:
 
 == Trace backends ==
 
-The tracetool script automates tedious trace event code generation and also
+The "tracetool" script automates tedious trace event code generation and also
 keeps the trace event declarations independent of the trace backend.  The trace
 events are not tightly coupled to a specific trace backend, such as LTTng or
-SystemTap.  Support for trace backends can be added by extending the tracetool
+SystemTap.  Support for trace backends can be added by extending the "tracetool"
 script.
 
 The trace backend is chosen at configure time and only one trace backend can
@@ -176,12 +181,12 @@ events at runtime inside QEMU:
 ==== Analyzing trace files ====
 
 The "simple" backend produces binary trace files that can be formatted with the
-simpletrace.py script.  The script takes the trace-events file and the binary
+simpletrace.py script.  The script takes the "trace-events" file and the binary
 trace:
 
     ./simpletrace.py trace-events trace-12345
 
-You must ensure that the same trace-events file was used to build QEMU,
+You must ensure that the same "trace-events" file was used to build QEMU,
 otherwise trace event declarations may have changed and output will not be
 consistent.
 
diff --git a/elf.h b/elf.h
index 523c972a6ba25bff0080526e5ba443f677f4b758..ffcac7e0b09a8349fc29f51a1f172e7b33118cad 100644 (file)
--- a/elf.h
+++ b/elf.h
@@ -106,6 +106,8 @@ typedef int64_t  Elf64_Sxword;
 #define EM_H8S          48      /* Hitachi H8S     */
 #define EM_LATTICEMICO32 138    /* LatticeMico32 */
 
+#define EM_UNICORE32    110     /* UniCore32 */
+
 /*
  * This is an interim value that we will use until the committee comes
  * up with a final number.
index 496c001c03ae69dbbeda856c5c50d3ef349a867b..7c2d29ff9831c6458f65fb8d03f94a0e353dd094 100644 (file)
@@ -77,15 +77,14 @@ extern uint16_t gen_opc_icount[OPC_BUF_SIZE];
 
 void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
 void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
-void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
-                 unsigned long searched_pc, int pc_pos, void *puc);
+void restore_state_to_opc(CPUState *env, struct TranslationBlock *tb,
+                          int pc_pos);
 
 void cpu_gen_init(void);
 int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
                  int *gen_code_size_ptr);
 int cpu_restore_state(struct TranslationBlock *tb,
-                      CPUState *env, unsigned long searched_pc,
-                      void *puc);
+                      CPUState *env, unsigned long searched_pc);
 void cpu_resume_from_signal(CPUState *env1, void *puc);
 void cpu_io_recompile(CPUState *env, void *retaddr);
 TranslationBlock *tb_gen_code(CPUState *env, 
diff --git a/exec.c b/exec.c
index 0c773a8ad9aa8d6d80136f052381e57cb909691a..308a86dcc021b94c99a099e36f381af2c19a58a7 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -1070,8 +1070,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
                 restore the CPU state */
 
                 current_tb_modified = 1;
-                cpu_restore_state(current_tb, env,
-                                  env->mem_io_pc, NULL);
+                cpu_restore_state(current_tb, env, env->mem_io_pc);
                 cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
                                      &current_flags);
             }
@@ -1179,7 +1178,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr,
                    restore the CPU state */
 
             current_tb_modified = 1;
-            cpu_restore_state(current_tb, env, pc, puc);
+            cpu_restore_state(current_tb, env, pc);
             cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
                                  &current_flags);
         }
@@ -1630,15 +1629,15 @@ static void cpu_unlink_tb(CPUState *env)
     spin_unlock(&interrupt_lock);
 }
 
+#ifndef CONFIG_USER_ONLY
 /* mask must never be zero, except for A20 change call */
-void cpu_interrupt(CPUState *env, int mask)
+static void tcg_handle_interrupt(CPUState *env, int mask)
 {
     int old_mask;
 
     old_mask = env->interrupt_request;
     env->interrupt_request |= mask;
 
-#ifndef CONFIG_USER_ONLY
     /*
      * If called from iothread context, wake the target cpu in
      * case its halted.
@@ -1647,21 +1646,29 @@ void cpu_interrupt(CPUState *env, int mask)
         qemu_cpu_kick(env);
         return;
     }
-#endif
 
     if (use_icount) {
         env->icount_decr.u16.high = 0xffff;
-#ifndef CONFIG_USER_ONLY
         if (!can_do_io(env)
             && (mask & ~old_mask) != 0) {
             cpu_abort(env, "Raised interrupt while not in I/O function");
         }
-#endif
     } else {
         cpu_unlink_tb(env);
     }
 }
 
+CPUInterruptHandler cpu_interrupt_handler = tcg_handle_interrupt;
+
+#else /* CONFIG_USER_ONLY */
+
+void cpu_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+    cpu_unlink_tb(env);
+}
+#endif /* CONFIG_USER_ONLY */
+
 void cpu_reset_interrupt(CPUState *env, int mask)
 {
     env->interrupt_request &= ~mask;
@@ -2621,6 +2628,7 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
     ram_addr_t orig_size = size;
     subpage_t *subpage;
 
+    assert(size);
     cpu_notify_set_memory(start_addr, size, phys_offset, log_dirty);
 
     if (phys_offset == IO_MEM_UNASSIGNED) {
@@ -2629,7 +2637,9 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
     region_offset &= TARGET_PAGE_MASK;
     size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
     end_addr = start_addr + (target_phys_addr_t)size;
-    for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
+
+    addr = start_addr;
+    do {
         p = phys_page_find(addr >> TARGET_PAGE_BITS);
         if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
             ram_addr_t orig_memory = p->phys_offset;
@@ -2681,7 +2691,8 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
             }
         }
         region_offset += TARGET_PAGE_SIZE;
-    }
+        addr += TARGET_PAGE_SIZE;
+    } while (addr != end_addr);
 
     /* since each CPU stores ram addresses in its TLB cache, we must
        reset the modified entries */
@@ -3272,7 +3283,7 @@ static void check_watchpoint(int offset, int len_mask, int flags)
                     cpu_abort(env, "check_watchpoint: could not find TB for "
                               "pc=%p", (void *)env->mem_io_pc);
                 }
-                cpu_restore_state(tb, env, env->mem_io_pc, NULL);
+                cpu_restore_state(tb, env, env->mem_io_pc);
                 tb_phys_invalidate(tb, -1);
                 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
                     env->exception_index = EXCP_DEBUG;
@@ -3938,7 +3949,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
             bounce.addr = addr;
             bounce.len = l;
             if (!is_write) {
-                cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
+                cpu_physical_memory_read(addr, bounce.buffer, l);
             }
             ptr = bounce.buffer;
         } else {
@@ -4259,7 +4270,7 @@ void stw_phys(target_phys_addr_t addr, uint32_t val)
 void stq_phys(target_phys_addr_t addr, uint64_t val)
 {
     val = tswap64(val);
-    cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
+    cpu_physical_memory_write(addr, &val, 8);
 }
 
 /* virtual memory access for debug (includes writing to ROM) */
@@ -4307,7 +4318,7 @@ void cpu_io_recompile(CPUState *env, void *retaddr)
                   retaddr);
     }
     n = env->icount_decr.u16.low + tb->icount;
-    cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
+    cpu_restore_state(tb, env, (unsigned long)retaddr);
     /* Calculate how many instructions had been executed before the fault
        occurred.  */
     n = n - env->icount_decr.u16.low;
index 3128e60cbf5a5901470fcf38e34f9f97fd658709..e82ce2332db0e076fb09f9a28e011e71324b23fd 100644 (file)
@@ -35,6 +35,17 @@ these four paragraphs for those parts of this code that are retained.
 
 =============================================================================*/
 
+/*----------------------------------------------------------------------------
+| This macro tests for minimum version of the GNU C compiler.
+*----------------------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define SOFTFLOAT_GNUC_PREREQ(maj, min) \
+         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define SOFTFLOAT_GNUC_PREREQ(maj, min) 0
+#endif
+
+
 /*----------------------------------------------------------------------------
 | Shifts `a' right by the number of bits given in `count'.  If any nonzero
 | bits are shifted off, they are ``jammed'' into the least significant bit of
@@ -616,6 +627,13 @@ static uint32_t estimateSqrt32( int16 aExp, uint32_t a )
 
 static int8 countLeadingZeros32( uint32_t a )
 {
+#if SOFTFLOAT_GNUC_PREREQ(3, 4)
+    if (a) {
+        return __builtin_clz(a);
+    } else {
+        return 32;
+    }
+#else
     static const int8 countLeadingZerosHigh[] = {
         8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
         3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
@@ -647,7 +665,7 @@ static int8 countLeadingZeros32( uint32_t a )
     }
     shiftCount += countLeadingZerosHigh[ a>>24 ];
     return shiftCount;
-
+#endif
 }
 
 /*----------------------------------------------------------------------------
@@ -657,6 +675,13 @@ static int8 countLeadingZeros32( uint32_t a )
 
 static int8 countLeadingZeros64( uint64_t a )
 {
+#if SOFTFLOAT_GNUC_PREREQ(3, 4)
+    if (a) {
+        return __builtin_clzll(a);
+    } else {
+        return 64;
+    }
+#else
     int8 shiftCount;
 
     shiftCount = 0;
@@ -668,7 +693,7 @@ static int8 countLeadingZeros64( uint64_t a )
     }
     shiftCount += countLeadingZeros32( a );
     return shiftCount;
-
+#endif
 }
 
 /*----------------------------------------------------------------------------
index 50355a4c3f8446cbf842de5409967577a506cd22..88486511ee23c7042f93cd918edf54b5e6320e9c 100644 (file)
@@ -263,6 +263,15 @@ int float32_is_quiet_nan( float32 a1 )
     return ( 0xFF800000 < ( a<<1 ) );
 }
 
+int float32_is_any_nan( float32 a1 )
+{
+    float32u u;
+    uint32_t a;
+    u.f = a1;
+    a = u.i;
+    return (a & ~(1 << 31)) > 0x7f800000U;
+}
+
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE double-precision conversion routines.
 *----------------------------------------------------------------------------*/
@@ -422,6 +431,16 @@ int float64_is_quiet_nan( float64 a1 )
 
 }
 
+int float64_is_any_nan( float64 a1 )
+{
+    float64u u;
+    uint64_t a;
+    u.f = a1;
+    a = u.i;
+
+    return (a & ~(1ULL << 63)) > LIT64 (0x7FF0000000000000 );
+}
+
 #ifdef FLOATX80
 
 /*----------------------------------------------------------------------------
@@ -511,4 +530,11 @@ int floatx80_is_quiet_nan( floatx80 a1 )
     return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (uint64_t) ( u.i.low<<1 );
 }
 
+int floatx80_is_any_nan( floatx80 a1 )
+{
+    floatx80u u;
+    u.f = a1;
+    return ((u.i.high & 0x7FFF) == 0x7FFF) && ( u.i.low<<1 );
+}
+
 #endif
index 80b5f288e36ff6ca0c3ea929b9a06af9082fc9d7..6afb74a152c9cf6240d62f5d317d5f66aea4ad92 100644 (file)
@@ -171,6 +171,15 @@ floatx80 int64_to_floatx80( int64_t STATUS_PARAM);
 float128 int64_to_float128( int64_t STATUS_PARAM);
 #endif
 
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE single-precision conversion constants.
+*----------------------------------------------------------------------------*/
+#define float32_zero (0.0)
+#define float32_one (1.0)
+#define float32_ln2 (0.6931471)
+#define float32_pi (3.1415926)
+#define float32_half (0.5)
+
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE single-precision conversion routines.
 *----------------------------------------------------------------------------*/
@@ -210,7 +219,7 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM)
 }
 float32 float32_rem( float32, float32  STATUS_PARAM);
 float32 float32_sqrt( float32  STATUS_PARAM);
-INLINE int float32_eq( float32 a, float32 b STATUS_PARAM)
+INLINE int float32_eq_quiet( float32 a, float32 b STATUS_PARAM)
 {
     return a == b;
 }
@@ -222,7 +231,7 @@ INLINE int float32_lt( float32 a, float32 b STATUS_PARAM)
 {
     return a < b;
 }
-INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
+INLINE int float32_eq( float32 a, float32 b STATUS_PARAM)
 {
     return a <= b && a >= b;
 }
@@ -237,12 +246,16 @@ INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
 INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
 {
     return isunordered(a, b);
-
+}
+INLINE int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM)
+{
+    return isunordered(a, b);
 }
 int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
 int float32_is_signaling_nan( float32 );
 int float32_is_quiet_nan( float32 );
+int float32_is_any_nan( float32 );
 
 INLINE float32 float32_abs(float32 a)
 {
@@ -271,11 +284,20 @@ INLINE float32 float32_is_zero(float32 a)
     return fpclassify(a) == FP_ZERO;
 }
 
-INLINE float32 float32_scalbn(float32 a, int n)
+INLINE float32 float32_scalbn(float32 a, int n STATUS_PARAM)
 {
     return scalbnf(a, n);
 }
 
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE double-precision conversion constants.
+*----------------------------------------------------------------------------*/
+#define float64_zero (0.0)
+#define float64_one (1.0)
+#define float64_ln2 (0.693147180559945)
+#define float64_pi (3.141592653589793)
+#define float64_half (0.5)
+
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE double-precision conversion routines.
 *----------------------------------------------------------------------------*/
@@ -318,7 +340,7 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM)
 }
 float64 float64_rem( float64, float64 STATUS_PARAM );
 float64 float64_sqrt( float64 STATUS_PARAM );
-INLINE int float64_eq( float64 a, float64 b STATUS_PARAM)
+INLINE int float64_eq_quiet( float64 a, float64 b STATUS_PARAM)
 {
     return a == b;
 }
@@ -330,7 +352,7 @@ INLINE int float64_lt( float64 a, float64 b STATUS_PARAM)
 {
     return a < b;
 }
-INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
+INLINE int float64_eq( float64 a, float64 b STATUS_PARAM)
 {
     return a <= b && a >= b;
 }
@@ -346,11 +368,15 @@ INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
 INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM)
 {
     return isunordered(a, b);
-
+}
+INLINE int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM)
+{
+    return isunordered(a, b);
 }
 int float64_compare( float64, float64 STATUS_PARAM );
 int float64_compare_quiet( float64, float64 STATUS_PARAM );
 int float64_is_signaling_nan( float64 );
+int float64_is_any_nan( float64 );
 int float64_is_quiet_nan( float64 );
 
 INLINE float64 float64_abs(float64 a)
@@ -380,13 +406,22 @@ INLINE float64 float64_is_zero(float64 a)
     return fpclassify(a) == FP_ZERO;
 }
 
-INLINE float64 float64_scalbn(float64 a, int n)
+INLINE float64 float64_scalbn(float64 a, int n STATUS_PARAM)
 {
     return scalbn(a, n);
 }
 
 #ifdef FLOATX80
 
+/*----------------------------------------------------------------------------
+| Software IEC/IEEE extended double-precision conversion constants.
+*----------------------------------------------------------------------------*/
+#define floatx80_zero (0.0L)
+#define floatx80_one (1.0L)
+#define floatx80_ln2 (0.69314718055994530943L)
+#define floatx80_pi (3.14159265358979323851L)
+#define floatx80_half (0.5L)
+
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE extended double-precision conversion routines.
 *----------------------------------------------------------------------------*/
@@ -422,7 +457,7 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM)
 }
 floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
 floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
-INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
+INLINE int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM)
 {
     return a == b;
 }
@@ -434,7 +469,7 @@ INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
 {
     return a < b;
 }
-INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
+INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
 {
     return a <= b && a >= b;
 }
@@ -450,12 +485,16 @@ INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
 INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
 {
     return isunordered(a, b);
-
+}
+INLINE int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM)
+{
+    return isunordered(a, b);
 }
 int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
 int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_is_signaling_nan( floatx80 );
 int floatx80_is_quiet_nan( floatx80 );
+int floatx80_is_any_nan( floatx80 );
 
 INLINE floatx80 floatx80_abs(floatx80 a)
 {
@@ -484,7 +523,7 @@ INLINE floatx80 floatx80_is_zero(floatx80 a)
     return fpclassify(a) == FP_ZERO;
 }
 
-INLINE floatx80 floatx80_scalbn(floatx80 a, int n)
+INLINE floatx80 floatx80_scalbn(floatx80 a, int n STATUS_PARAM)
 {
     return scalbnl(a, n);
 }
index 4b65de64a8a413bd872bf27f66a62389d2e3903a..9d68aae9d550c92ac5e2e0257527983674c9f58a 100644 (file)
@@ -93,7 +93,7 @@ float16 float16_maybe_silence_nan(float16 a_)
 {
     if (float16_is_signaling_nan(a_)) {
 #if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4)
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         return float16_default_nan;
 #  else
 #    error Rules for silencing a signaling NaN are target-specific
@@ -184,7 +184,7 @@ float32 float32_maybe_silence_nan( float32 a_ )
 {
     if (float32_is_signaling_nan(a_)) {
 #if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4)
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         return float32_default_nan;
 #  else
 #    error Rules for silencing a signaling NaN are target-specific
@@ -430,7 +430,7 @@ float64 float64_maybe_silence_nan( float64 a_ )
 {
     if (float64_is_signaling_nan(a_)) {
 #if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4)
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         return float64_default_nan;
 #  else
 #    error Rules for silencing a signaling NaN are target-specific
@@ -578,7 +578,7 @@ floatx80 floatx80_maybe_silence_nan( floatx80 a )
 {
     if (floatx80_is_signaling_nan(a)) {
 #if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4)
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         a.low = floatx80_default_nan_low;
         a.high = floatx80_default_nan_high;
 #  else
@@ -603,9 +603,15 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM)
     commonNaNT z;
 
     if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
-    z.sign = a.high>>15;
-    z.low = 0;
-    z.high = a.low;
+    if ( a.low >> 63 ) {
+        z.sign = a.high >> 15;
+        z.low = 0;
+        z.high = a.low << 1;
+    } else {
+        z.sign = floatx80_default_nan_high >> 15;
+        z.low = 0;
+        z.high = floatx80_default_nan_low << 1;
+    }
     return z;
 }
 
@@ -624,11 +630,14 @@ static floatx80 commonNaNToFloatx80( commonNaNT a STATUS_PARAM)
         return z;
     }
 
-    if (a.high)
-        z.low = a.high;
-    else
+    if (a.high >> 1) {
+        z.low = LIT64( 0x8000000000000000 ) | a.high >> 1;
+        z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF;
+    } else {
         z.low = floatx80_default_nan_low;
-    z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF;
+        z.high = floatx80_default_nan_high;
+    }
+
     return z;
 }
 
@@ -721,7 +730,7 @@ float128 float128_maybe_silence_nan( float128 a )
 {
     if (float128_is_signaling_nan(a)) {
 #if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4)
+#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         a.low = float128_default_nan_low;
         a.high = float128_default_nan_high;
 #  else
index 08e4ae03d969aa2599d792deedf959f0c7cabe72..baba1dc44b812c978ba04cb0f37718e4e67acab6 100644 (file)
@@ -2314,33 +2314,33 @@ float32 float32_log2( float32 a STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the single-precision floating-point value `a' is equal to
-| the corresponding value `b', and 0 otherwise.  The comparison is performed
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  Otherwise, the comparison is performed
 | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int float32_eq( float32 a, float32 b STATUS_PARAM )
 {
+    uint32_t av, bv;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
          || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
        ) {
-        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid STATUS_VAR);
-        }
+        float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    return ( float32_val(a) == float32_val(b) ) ||
-            ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 );
-
+    av = float32_val(a);
+    bv = float32_val(b);
+    return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
 }
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the single-precision floating-point value `a' is less than
-| or equal to the corresponding value `b', and 0 otherwise.  The comparison
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
+| or equal to the corresponding value `b', and 0 otherwise.  The invalid
+| exception is raised if either operand is a NaN.  The comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int float32_le( float32 a, float32 b STATUS_PARAM )
@@ -2367,8 +2367,9 @@ int float32_le( float32 a, float32 b STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the single-precision floating-point value `a' is less than
-| the corresponding value `b', and 0 otherwise.  The comparison is performed
-| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  The comparison is performed according
+| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int float32_lt( float32 a, float32 b STATUS_PARAM )
@@ -2394,15 +2395,14 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
 }
 
 /*----------------------------------------------------------------------------
-| Returns 1 if the single-precision floating-point value `a' is equal to
-| the corresponding value `b', and 0 otherwise.  The invalid exception is
-| raised if either operand is a NaN.  Otherwise, the comparison is performed
-| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+| Returns 1 if the single-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  The invalid exception is raised if either
+| operand is a NaN.  The comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
-int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
+int float32_unordered( float32 a, float32 b STATUS_PARAM )
 {
-    uint32_t av, bv;
     a = float32_squash_input_denormal(a STATUS_VAR);
     b = float32_squash_input_denormal(b STATUS_VAR);
 
@@ -2410,12 +2410,33 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
          || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
-        return 0;
+        return 1;
     }
-    av = float32_val(a);
-    bv = float32_val(b);
-    return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is equal to
+| the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.  The comparison is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_eq_quiet( float32 a, float32 b STATUS_PARAM )
+{
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 0;
+    }
+    return ( float32_val(a) == float32_val(b) ) ||
+            ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 );
 }
 
 /*----------------------------------------------------------------------------
@@ -2480,6 +2501,29 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  Quiet NaNs do not cause an exception.  The
+| comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM )
+{
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 1;
+    }
+    return 0;
+}
+
 /*----------------------------------------------------------------------------
 | Returns the result of converting the double-precision floating-point value
 | `a' to the 32-bit two's complement integer format.  The conversion is
@@ -3536,7 +3580,8 @@ float64 float64_log2( float64 a STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the double-precision floating-point value `a' is equal to the
-| corresponding value `b', and 0 otherwise.  The comparison is performed
+| corresponding value `b', and 0 otherwise.  The invalid exception is raised
+| if either operand is a NaN.  Otherwise, the comparison is performed
 | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
@@ -3549,9 +3594,7 @@ int float64_eq( float64 a, float64 b STATUS_PARAM )
     if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
          || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
        ) {
-        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid STATUS_VAR);
-        }
+        float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
     av = float64_val(a);
@@ -3562,9 +3605,9 @@ int float64_eq( float64 a, float64 b STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the double-precision floating-point value `a' is less than or
-| equal to the corresponding value `b', and 0 otherwise.  The comparison is
-| performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
+| equal to the corresponding value `b', and 0 otherwise.  The invalid
+| exception is raised if either operand is a NaN.  The comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int float64_le( float64 a, float64 b STATUS_PARAM )
@@ -3591,8 +3634,9 @@ int float64_le( float64 a, float64 b STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the double-precision floating-point value `a' is less than
-| the corresponding value `b', and 0 otherwise.  The comparison is performed
-| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  The comparison is performed according
+| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int float64_lt( float64 a, float64 b STATUS_PARAM )
@@ -3617,14 +3661,35 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  The invalid exception is raised if either
+| operand is a NaN.  The comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_unordered( float64 a, float64 b STATUS_PARAM )
+{
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 1;
+    }
+    return 0;
+}
+
 /*----------------------------------------------------------------------------
 | Returns 1 if the double-precision floating-point value `a' is equal to the
-| corresponding value `b', and 0 otherwise.  The invalid exception is raised
-| if either operand is a NaN.  Otherwise, the comparison is performed
-| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+| corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.The comparison is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
-int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
+int float64_eq_quiet( float64 a, float64 b STATUS_PARAM )
 {
     uint64_t av, bv;
     a = float64_squash_input_denormal(a STATUS_VAR);
@@ -3633,7 +3698,9 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
     if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
          || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
        ) {
-        float_raise( float_flag_invalid STATUS_VAR);
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
         return 0;
     }
     av = float64_val(a);
@@ -3704,6 +3771,29 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  Quiet NaNs do not cause an exception.  The
+| comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM )
+{
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 1;
+    }
+    return 0;
+}
+
 #ifdef FLOATX80
 
 /*----------------------------------------------------------------------------
@@ -4501,10 +4591,10 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
 }
 
 /*----------------------------------------------------------------------------
-| Returns 1 if the extended double-precision floating-point value `a' is
-| equal to the corresponding value `b', and 0 otherwise.  The comparison is
-| performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
+| Returns 1 if the extended double-precision floating-point value `a' is equal
+| to the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  Otherwise, the comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
@@ -4515,10 +4605,7 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
          || (    ( extractFloatx80Exp( b ) == 0x7FFF )
               && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
        ) {
-        if (    floatx80_is_signaling_nan( a )
-             || floatx80_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid STATUS_VAR);
-        }
+        float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
     return
@@ -4533,8 +4620,9 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
 /*----------------------------------------------------------------------------
 | Returns 1 if the extended double-precision floating-point value `a' is
 | less than or equal to the corresponding value `b', and 0 otherwise.  The
-| comparison is performed according to the IEC/IEEE Standard for Binary
-| Floating-Point Arithmetic.
+| invalid exception is raised if either operand is a NaN.  The comparison is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
@@ -4565,9 +4653,9 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the extended double-precision floating-point value `a' is
-| less than the corresponding value `b', and 0 otherwise.  The comparison
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
+| less than the corresponding value `b', and 0 otherwise.  The invalid
+| exception is raised if either operand is a NaN.  The comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
@@ -4597,13 +4685,32 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
 }
 
 /*----------------------------------------------------------------------------
-| Returns 1 if the extended double-precision floating-point value `a' is equal
-| to the corresponding value `b', and 0 otherwise.  The invalid exception is
-| raised if either operand is a NaN.  Otherwise, the comparison is performed
-| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+| Returns 1 if the extended double-precision floating-point values `a' and `b'
+| cannot be compared, and 0 otherwise.  The invalid exception is raised if
+| either operand is a NaN.   The comparison is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
+int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 1;
+    }
+    return 0;
+}
 
-int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is
+| equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+| cause an exception.  The comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM )
 {
 
     if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
@@ -4611,7 +4718,10 @@ int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
          || (    ( extractFloatx80Exp( b ) == 0x7FFF )
               && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
        ) {
-        float_raise( float_flag_invalid STATUS_VAR);
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
         return 0;
     }
     return
@@ -4695,6 +4805,28 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point values `a' and `b'
+| cannot be compared, and 0 otherwise.  Quiet NaNs do not cause an exception.
+| The comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 1;
+    }
+    return 0;
+}
+
 #endif
 
 #ifdef FLOAT128
@@ -5625,7 +5757,8 @@ float128 float128_sqrt( float128 a STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the quadruple-precision floating-point value `a' is equal to
-| the corresponding value `b', and 0 otherwise.  The comparison is performed
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  Otherwise, the comparison is performed
 | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
@@ -5637,10 +5770,7 @@ int float128_eq( float128 a, float128 b STATUS_PARAM )
          || (    ( extractFloat128Exp( b ) == 0x7FFF )
               && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
        ) {
-        if (    float128_is_signaling_nan( a )
-             || float128_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid STATUS_VAR);
-        }
+        float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
     return
@@ -5654,9 +5784,9 @@ int float128_eq( float128 a, float128 b STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the quadruple-precision floating-point value `a' is less than
-| or equal to the corresponding value `b', and 0 otherwise.  The comparison
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
+| or equal to the corresponding value `b', and 0 otherwise.  The invalid
+| exception is raised if either operand is a NaN.  The comparison is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int float128_le( float128 a, float128 b STATUS_PARAM )
@@ -5687,8 +5817,9 @@ int float128_le( float128 a, float128 b STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the quadruple-precision floating-point value `a' is less than
-| the corresponding value `b', and 0 otherwise.  The comparison is performed
-| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+| the corresponding value `b', and 0 otherwise.  The invalid exception is
+| raised if either operand is a NaN.  The comparison is performed according
+| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
 int float128_lt( float128 a, float128 b STATUS_PARAM )
@@ -5717,14 +5848,34 @@ int float128_lt( float128 a, float128 b STATUS_PARAM )
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  The invalid exception is raised if either
+| operand is a NaN. The comparison is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_unordered( float128 a, float128 b STATUS_PARAM )
+{
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return 1;
+    }
+    return 0;
+}
+
 /*----------------------------------------------------------------------------
 | Returns 1 if the quadruple-precision floating-point value `a' is equal to
-| the corresponding value `b', and 0 otherwise.  The invalid exception is
-| raised if either operand is a NaN.  Otherwise, the comparison is performed
-| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+| the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+| exception.  The comparison is performed according to the IEC/IEEE Standard
+| for Binary Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
-int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
+int float128_eq_quiet( float128 a, float128 b STATUS_PARAM )
 {
 
     if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
@@ -5732,7 +5883,10 @@ int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
          || (    ( extractFloat128Exp( b ) == 0x7FFF )
               && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
        ) {
-        float_raise( float_flag_invalid STATUS_VAR);
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
         return 0;
     }
     return
@@ -5816,6 +5970,29 @@ int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise.  Quiet NaNs do not cause an exception.  The
+| comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM )
+{
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return 1;
+    }
+    return 0;
+}
+
 #endif
 
 /* misc functions */
@@ -6013,6 +6190,52 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM )  \
 COMPARE(32, 0xff)
 COMPARE(64, 0x7ff)
 
+INLINE int floatx80_compare_internal( floatx80 a, floatx80 b,
+                                      int is_quiet STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (( ( extractFloatx80Exp( a ) == 0x7fff ) &&
+          ( extractFloatx80Frac( a )<<1 ) ) ||
+        ( ( extractFloatx80Exp( b ) == 0x7fff ) &&
+          ( extractFloatx80Frac( b )<<1 ) )) {
+        if (!is_quiet ||
+            floatx80_is_signaling_nan( a ) ||
+            floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return float_relation_unordered;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+
+        if ( ( ( (uint16_t) ( ( a.high | b.high ) << 1 ) ) == 0) &&
+             ( ( a.low | b.low ) == 0 ) ) {
+            /* zero case */
+            return float_relation_equal;
+        } else {
+            return 1 - (2 * aSign);
+        }
+    } else {
+        if (a.low == b.low && a.high == b.high) {
+            return float_relation_equal;
+        } else {
+            return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) ));
+        }
+    }
+}
+
+int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    return floatx80_compare_internal(a, b, 0 STATUS_VAR);
+}
+
+int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
+{
+    return floatx80_compare_internal(a, b, 1 STATUS_VAR);
+}
+
 INLINE int float128_compare_internal( float128 a, float128 b,
                                       int is_quiet STATUS_PARAM )
 {
@@ -6057,11 +6280,60 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
     return float128_compare_internal(a, b, 1 STATUS_VAR);
 }
 
+/* min() and max() functions. These can't be implemented as
+ * 'compare and pick one input' because that would mishandle
+ * NaNs and +0 vs -0.
+ */
+#define MINMAX(s, nan_exp)                                              \
+INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b,     \
+                                        int ismin STATUS_PARAM )        \
+{                                                                       \
+    flag aSign, bSign;                                                  \
+    uint ## s ## _t av, bv;                                             \
+    a = float ## s ## _squash_input_denormal(a STATUS_VAR);             \
+    b = float ## s ## _squash_input_denormal(b STATUS_VAR);             \
+    if (float ## s ## _is_any_nan(a) ||                                 \
+        float ## s ## _is_any_nan(b)) {                                 \
+        return propagateFloat ## s ## NaN(a, b STATUS_VAR);             \
+    }                                                                   \
+    aSign = extractFloat ## s ## Sign(a);                               \
+    bSign = extractFloat ## s ## Sign(b);                               \
+    av = float ## s ## _val(a);                                         \
+    bv = float ## s ## _val(b);                                         \
+    if (aSign != bSign) {                                               \
+        if (ismin) {                                                    \
+            return aSign ? a : b;                                       \
+        } else {                                                        \
+            return aSign ? b : a;                                       \
+        }                                                               \
+    } else {                                                            \
+        if (ismin) {                                                    \
+            return (aSign ^ (av < bv)) ? a : b;                         \
+        } else {                                                        \
+            return (aSign ^ (av < bv)) ? b : a;                         \
+        }                                                               \
+    }                                                                   \
+}                                                                       \
+                                                                        \
+float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM)  \
+{                                                                       \
+    return float ## s ## _minmax(a, b, 1 STATUS_VAR);                   \
+}                                                                       \
+                                                                        \
+float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM)  \
+{                                                                       \
+    return float ## s ## _minmax(a, b, 0 STATUS_VAR);                   \
+}
+
+MINMAX(32, 0xff)
+MINMAX(64, 0x7ff)
+
+
 /* Multiply A by 2 raised to the power N.  */
 float32 float32_scalbn( float32 a, int n STATUS_PARAM )
 {
     flag aSign;
-    int16 aExp;
+    int16_t aExp;
     uint32_t aSig;
 
     a = float32_squash_input_denormal(a STATUS_VAR);
@@ -6070,6 +6342,9 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
     aSign = extractFloat32Sign( a );
 
     if ( aExp == 0xFF ) {
+        if ( aSig ) {
+            return propagateFloat32NaN( a, a STATUS_VAR );
+        }
         return a;
     }
     if ( aExp != 0 )
@@ -6077,6 +6352,12 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
     else if ( aSig == 0 )
         return a;
 
+    if (n > 0x200) {
+        n = 0x200;
+    } else if (n < -0x200) {
+        n = -0x200;
+    }
+
     aExp += n - 1;
     aSig <<= 7;
     return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
@@ -6085,7 +6366,7 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
 float64 float64_scalbn( float64 a, int n STATUS_PARAM )
 {
     flag aSign;
-    int16 aExp;
+    int16_t aExp;
     uint64_t aSig;
 
     a = float64_squash_input_denormal(a STATUS_VAR);
@@ -6094,6 +6375,9 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
     aSign = extractFloat64Sign( a );
 
     if ( aExp == 0x7FF ) {
+        if ( aSig ) {
+            return propagateFloat64NaN( a, a STATUS_VAR );
+        }
         return a;
     }
     if ( aExp != 0 )
@@ -6101,6 +6385,12 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
     else if ( aSig == 0 )
         return a;
 
+    if (n > 0x1000) {
+        n = 0x1000;
+    } else if (n < -0x1000) {
+        n = -0x1000;
+    }
+
     aExp += n - 1;
     aSig <<= 10;
     return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
@@ -6110,19 +6400,29 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
 floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
 {
     flag aSign;
-    int16 aExp;
+    int32_t aExp;
     uint64_t aSig;
 
     aSig = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
 
-    if ( aExp == 0x7FF ) {
+    if ( aExp == 0x7FFF ) {
+        if ( aSig<<1 ) {
+            return propagateFloatx80NaN( a, a STATUS_VAR );
+        }
         return a;
     }
+
     if (aExp == 0 && aSig == 0)
         return a;
 
+    if (n > 0x10000) {
+        n = 0x10000;
+    } else if (n < -0x10000) {
+        n = -0x10000;
+    }
+
     aExp += n;
     return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision),
                                           aSign, aExp, aSig, 0 STATUS_VAR );
@@ -6133,7 +6433,7 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
 float128 float128_scalbn( float128 a, int n STATUS_PARAM )
 {
     flag aSign;
-    int32 aExp;
+    int32_t aExp;
     uint64_t aSig0, aSig1;
 
     aSig1 = extractFloat128Frac1( a );
@@ -6141,6 +6441,9 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
     aExp = extractFloat128Exp( a );
     aSign = extractFloat128Sign( a );
     if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return propagateFloat128NaN( a, a STATUS_VAR );
+        }
         return a;
     }
     if ( aExp != 0 )
@@ -6148,6 +6451,12 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
     else if ( aSig0 == 0 && aSig1 == 0 )
         return a;
 
+    if (n > 0x10000) {
+        n = 0x10000;
+    } else if (n < -0x10000) {
+        n = -0x10000;
+    }
+
     aExp += n - 1;
     return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1
                                           STATUS_VAR );
index 5d05fa5cf872407fa02fec93493fbfd07a096d4a..5eff0858f1247e638bf02d380b6a0468a3b8aedb 100644 (file)
@@ -68,7 +68,7 @@ typedef int64_t int64;
 #define LIT64( a ) a##LL
 #define INLINE static inline
 
-#if defined(TARGET_MIPS) || defined(TARGET_SH4)
+#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
 #define SNAN_BIT_IS_ONE                1
 #else
 #define SNAN_BIT_IS_ONE                0
@@ -154,6 +154,7 @@ typedef struct {
     uint64_t low;
     uint16_t high;
 } floatx80;
+#define make_floatx80(exp, mant) ((floatx80) { mant, exp })
 #endif
 #ifdef FLOAT128
 typedef struct {
@@ -211,6 +212,10 @@ typedef struct float_status {
 
 void set_float_rounding_mode(int val STATUS_PARAM);
 void set_float_exception_flags(int val STATUS_PARAM);
+INLINE void set_float_detect_tininess(int val STATUS_PARAM)
+{
+    STATUS(float_detect_tininess) = val;
+}
 INLINE void set_flush_to_zero(flag val STATUS_PARAM)
 {
     STATUS(flush_to_zero) = val;
@@ -319,11 +324,15 @@ float32 float32_log2( float32 STATUS_PARAM );
 int float32_eq( float32, float32 STATUS_PARAM );
 int float32_le( float32, float32 STATUS_PARAM );
 int float32_lt( float32, float32 STATUS_PARAM );
-int float32_eq_signaling( float32, float32 STATUS_PARAM );
+int float32_unordered( float32, float32 STATUS_PARAM );
+int float32_eq_quiet( float32, float32 STATUS_PARAM );
 int float32_le_quiet( float32, float32 STATUS_PARAM );
 int float32_lt_quiet( float32, float32 STATUS_PARAM );
+int float32_unordered_quiet( float32, float32 STATUS_PARAM );
 int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
+float32 float32_min(float32, float32 STATUS_PARAM);
+float32 float32_max(float32, float32 STATUS_PARAM);
 int float32_is_quiet_nan( float32 );
 int float32_is_signaling_nan( float32 );
 float32 float32_maybe_silence_nan( float32 );
@@ -378,6 +387,7 @@ INLINE float32 float32_set_sign(float32 a, int sign)
 #define float32_zero make_float32(0)
 #define float32_one make_float32(0x3f800000)
 #define float32_ln2 make_float32(0x3f317218)
+#define float32_pi make_float32(0x40490fdb)
 #define float32_half make_float32(0x3f000000)
 #define float32_infinity make_float32(0x7f800000)
 
@@ -431,11 +441,15 @@ float64 float64_log2( float64 STATUS_PARAM );
 int float64_eq( float64, float64 STATUS_PARAM );
 int float64_le( float64, float64 STATUS_PARAM );
 int float64_lt( float64, float64 STATUS_PARAM );
-int float64_eq_signaling( float64, float64 STATUS_PARAM );
+int float64_unordered( float64, float64 STATUS_PARAM );
+int float64_eq_quiet( float64, float64 STATUS_PARAM );
 int float64_le_quiet( float64, float64 STATUS_PARAM );
 int float64_lt_quiet( float64, float64 STATUS_PARAM );
+int float64_unordered_quiet( float64, float64 STATUS_PARAM );
 int float64_compare( float64, float64 STATUS_PARAM );
 int float64_compare_quiet( float64, float64 STATUS_PARAM );
+float64 float64_min(float64, float64 STATUS_PARAM);
+float64 float64_max(float64, float64 STATUS_PARAM);
 int float64_is_quiet_nan( float64 a );
 int float64_is_signaling_nan( float64 );
 float64 float64_maybe_silence_nan( float64 );
@@ -486,6 +500,7 @@ INLINE float64 float64_set_sign(float64 a, int sign)
 #define float64_zero make_float64(0)
 #define float64_one make_float64(0x3ff0000000000000LL)
 #define float64_ln2 make_float64(0x3fe62e42fefa39efLL)
+#define float64_pi make_float64(0x400921fb54442d18LL)
 #define float64_half make_float64(0x3fe0000000000000LL)
 #define float64_infinity make_float64(0x7ff0000000000000LL)
 
@@ -530,9 +545,13 @@ floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
 int floatx80_eq( floatx80, floatx80 STATUS_PARAM );
 int floatx80_le( floatx80, floatx80 STATUS_PARAM );
 int floatx80_lt( floatx80, floatx80 STATUS_PARAM );
-int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
+int floatx80_unordered( floatx80, floatx80 STATUS_PARAM );
+int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_unordered_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
+int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_is_quiet_nan( floatx80 );
 int floatx80_is_signaling_nan( floatx80 );
 floatx80 floatx80_maybe_silence_nan( floatx80 );
@@ -552,7 +571,7 @@ INLINE floatx80 floatx80_chs(floatx80 a)
 
 INLINE int floatx80_is_infinity(floatx80 a)
 {
-    return (a.high & 0x7fff) == 0x7fff && a.low == 0;
+    return (a.high & 0x7fff) == 0x7fff && a.low == 0x8000000000000000LL;
 }
 
 INLINE int floatx80_is_neg(floatx80 a)
@@ -570,6 +589,13 @@ INLINE int floatx80_is_any_nan(floatx80 a)
     return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
 }
 
+#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL)
+#define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL)
+#define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL)
+#define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL)
+#define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL)
+#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL)
+
 /*----------------------------------------------------------------------------
 | The pattern for a default generated extended double-precision NaN.  The
 | `high' and `low' values hold the most- and least-significant bits,
@@ -613,9 +639,11 @@ float128 float128_sqrt( float128 STATUS_PARAM );
 int float128_eq( float128, float128 STATUS_PARAM );
 int float128_le( float128, float128 STATUS_PARAM );
 int float128_lt( float128, float128 STATUS_PARAM );
-int float128_eq_signaling( float128, float128 STATUS_PARAM );
+int float128_unordered( float128, float128 STATUS_PARAM );
+int float128_eq_quiet( float128, float128 STATUS_PARAM );
 int float128_le_quiet( float128, float128 STATUS_PARAM );
 int float128_lt_quiet( float128, float128 STATUS_PARAM );
+int float128_unordered_quiet( float128, float128 STATUS_PARAM );
 int float128_compare( float128, float128 STATUS_PARAM );
 int float128_compare_quiet( float128, float128 STATUS_PARAM );
 int float128_is_quiet_nan( float128 );
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
new file mode 100644 (file)
index 0000000..126e60e
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef _FILEOP_H
+#define _FILEOP_H
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/vfs.h>
+#define SM_LOCAL_MODE_BITS    0600
+#define SM_LOCAL_DIR_MODE_BITS    0700
+
+typedef enum
+{
+    /*
+     * Server will try to set uid/gid.
+     * On failure ignore the error.
+     */
+    SM_NONE = 0,
+    /*
+     * uid/gid set on fileserver files
+     */
+    SM_PASSTHROUGH = 1,
+    /*
+     * uid/gid part of xattr
+     */
+    SM_MAPPED,
+} SecModel;
+
+typedef struct FsCred
+{
+    uid_t   fc_uid;
+    gid_t   fc_gid;
+    mode_t  fc_mode;
+    dev_t   fc_rdev;
+} FsCred;
+
+struct xattr_operations;
+
+typedef struct FsContext
+{
+    char *fs_root;
+    SecModel fs_sm;
+    uid_t uid;
+    struct xattr_operations **xops;
+} FsContext;
+
+void cred_init(FsCred *);
+
+typedef struct FileOperations
+{
+    int (*lstat)(FsContext *, const char *, struct stat *);
+    ssize_t (*readlink)(FsContext *, const char *, char *, size_t);
+    int (*chmod)(FsContext *, const char *, FsCred *);
+    int (*chown)(FsContext *, const char *, FsCred *);
+    int (*mknod)(FsContext *, const char *, FsCred *);
+    int (*utimensat)(FsContext *, const char *, const struct timespec *);
+    int (*remove)(FsContext *, const char *);
+    int (*symlink)(FsContext *, const char *, const char *, FsCred *);
+    int (*link)(FsContext *, const char *, const char *);
+    int (*setuid)(FsContext *, uid_t);
+    int (*close)(FsContext *, int);
+    int (*closedir)(FsContext *, DIR *);
+    DIR *(*opendir)(FsContext *, const char *);
+    int (*open)(FsContext *, const char *, int);
+    int (*open2)(FsContext *, const char *, int, FsCred *);
+    void (*rewinddir)(FsContext *, DIR *);
+    off_t (*telldir)(FsContext *, DIR *);
+    struct dirent *(*readdir)(FsContext *, DIR *);
+    void (*seekdir)(FsContext *, DIR *, off_t);
+    ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
+    ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
+    int (*mkdir)(FsContext *, const char *, FsCred *);
+    int (*fstat)(FsContext *, int, struct stat *);
+    int (*rename)(FsContext *, const char *, const char *);
+    int (*truncate)(FsContext *, const char *, off_t);
+    int (*fsync)(FsContext *, int, int);
+    int (*statfs)(FsContext *s, const char *path, struct statfs *stbuf);
+    ssize_t (*lgetxattr)(FsContext *, const char *,
+                         const char *, void *, size_t);
+    ssize_t (*llistxattr)(FsContext *, const char *, void *, size_t);
+    int (*lsetxattr)(FsContext *, const char *,
+                     const char *, void *, size_t, int);
+    int (*lremovexattr)(FsContext *, const char *, const char *);
+    void *opaque;
+} FileOperations;
+
+static inline const char *rpath(FsContext *ctx, const char *path)
+{
+    /* FIXME: so wrong... */
+    static char buffer[4096];
+    snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
+    return buffer;
+}
+#endif
index a704043bebdd703151eb5e66e5819f5d87324122..f9f08d3e1b1ace58e53f93a2fd251712f6564923 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef QEMU_FSDEV_H
 #define QEMU_FSDEV_H
 #include "qemu-option.h"
-#include "hw/file-op-9p.h"
+#include "file-op-9p.h"
 
 
 /*
index 1e9f9312dea51067242219b0493c2fa6614d2725..0838948c5cda3c12f8211dab4ef0348dbb5cc180 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
 enum {
     GDB_SIGNAL_0 = 0,
     GDB_SIGNAL_INT = 2,
+    GDB_SIGNAL_QUIT = 3,
     GDB_SIGNAL_TRAP = 5,
+    GDB_SIGNAL_ABRT = 6,
+    GDB_SIGNAL_ALRM = 14,
+    GDB_SIGNAL_IO = 23,
+    GDB_SIGNAL_XCPU = 24,
     GDB_SIGNAL_UNKNOWN = 143
 };
 
@@ -2270,14 +2275,11 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
     const char *type;
     int ret;
 
-    if (running || (reason != VMSTOP_DEBUG && reason != VMSTOP_USER) ||
-        s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
+    if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
         return;
     }
-    /* disable single step if it was enable */
-    cpu_single_step(env, 0);
-
-    if (reason == VMSTOP_DEBUG) {
+    switch (reason) {
+    case VMSTOP_DEBUG:
         if (env->watchpoint_hit) {
             switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
             case BP_MEM_READ:
@@ -2294,17 +2296,44 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
                      "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
                      GDB_SIGNAL_TRAP, gdb_id(env), type,
                      env->watchpoint_hit->vaddr);
-            put_packet(s, buf);
             env->watchpoint_hit = NULL;
-            return;
+            goto send_packet;
         }
-       tb_flush(env);
+        tb_flush(env);
         ret = GDB_SIGNAL_TRAP;
-    } else {
+        break;
+    case VMSTOP_USER:
         ret = GDB_SIGNAL_INT;
+        break;
+    case VMSTOP_SHUTDOWN:
+        ret = GDB_SIGNAL_QUIT;
+        break;
+    case VMSTOP_DISKFULL:
+        ret = GDB_SIGNAL_IO;
+        break;
+    case VMSTOP_WATCHDOG:
+        ret = GDB_SIGNAL_ALRM;
+        break;
+    case VMSTOP_PANIC:
+        ret = GDB_SIGNAL_ABRT;
+        break;
+    case VMSTOP_SAVEVM:
+    case VMSTOP_LOADVM:
+        return;
+    case VMSTOP_MIGRATE:
+        ret = GDB_SIGNAL_XCPU;
+        break;
+    default:
+        ret = GDB_SIGNAL_UNKNOWN;
+        break;
     }
     snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(env));
+
+send_packet:
     put_packet(s, buf);
+
+    /* disable single step if it was enabled */
+    cpu_single_step(env, 0);
 }
 #endif
 
index 8879da633525f3ecfe78b64092f7b3cec6397067..5fb3829781595029508156ea16e4d73ed4e9f92e 100644 (file)
@@ -29,7 +29,7 @@ static void gen_icount_end(TranslationBlock *tb, int num_insns)
     if (use_icount) {
         *icount_arg = num_insns;
         gen_set_label(icount_label);
-        tcg_gen_exit_tb((long)tb + 2);
+        tcg_gen_exit_tb((tcg_target_long)tb + 2);
     }
 }
 
diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c
new file mode 100644 (file)
index 0000000..6b18842
--- /dev/null
@@ -0,0 +1,645 @@
+/*
+ * Virtio 9p PDU debug
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include "virtio.h"
+#include "pc.h"
+#include "virtio-9p.h"
+#include "virtio-9p-debug.h"
+
+#define BUG_ON(cond) assert(!(cond))
+
+static FILE *llogfile;
+
+static struct iovec *get_sg(V9fsPDU *pdu, int rx)
+{
+    if (rx) {
+        return pdu->elem.in_sg;
+    }
+    return pdu->elem.out_sg;
+}
+
+static int get_sg_count(V9fsPDU *pdu, int rx)
+{
+    if (rx) {
+        return pdu->elem.in_num;
+    }
+    return pdu->elem.out_num;
+
+}
+
+static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp,
+                        const char *name)
+{
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
+    size_t offset = *offsetp;
+    struct iovec *sg = get_sg(pdu, rx);
+    int8_t value;
+
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
+
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
+    fprintf(llogfile, "%s=0x%x", name, value);
+    *offsetp = offset;
+}
+
+static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp,
+                        const char *name)
+{
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    int16_t value;
+
+
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
+
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
+    fprintf(llogfile, "%s=0x%x", name, value);
+    *offsetp = offset;
+}
+
+static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp,
+                        const char *name)
+{
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    int32_t value;
+
+
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
+
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
+    fprintf(llogfile, "%s=0x%x", name, value);
+    *offsetp = offset;
+}
+
+static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp,
+                        const char *name)
+{
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    int64_t value;
+
+
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
+
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
+    fprintf(llogfile, "%s=0x%" PRIx64, name, value);
+    *offsetp = offset;
+}
+
+static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    int sg_count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    uint16_t tmp_size, size;
+    size_t result;
+    size_t copied = 0;
+    int i = 0;
+
+    /* get the size */
+    copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size));
+    BUG_ON(copied != sizeof(tmp_size));
+    size = le16_to_cpupu(&tmp_size);
+    offset += copied;
+
+    fprintf(llogfile, "%s=", name);
+    for (i = 0; size && i < sg_count; i++) {
+        size_t len;
+        if (offset >= sg[i].iov_len) {
+            /* skip this sg */
+            offset -= sg[i].iov_len;
+            continue;
+        } else {
+            len = MIN(sg[i].iov_len - offset, size);
+            result = fwrite(sg[i].iov_base + offset, 1, len, llogfile);
+            BUG_ON(result != len);
+            size -= len;
+            copied += len;
+            if (size) {
+                offset = 0;
+                continue;
+            }
+        }
+    }
+    *offsetp += copied;
+}
+
+static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    fprintf(llogfile, "%s={", name);
+    pprint_int8(pdu, rx, offsetp, "type");
+    pprint_int32(pdu, rx, offsetp, ", version");
+    pprint_int64(pdu, rx, offsetp, ", path");
+    fprintf(llogfile, "}");
+}
+
+static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    fprintf(llogfile, "%s={", name);
+    pprint_int16(pdu, rx, offsetp, "size");
+    pprint_int16(pdu, rx, offsetp, ", type");
+    pprint_int32(pdu, rx, offsetp, ", dev");
+    pprint_qid(pdu, rx, offsetp, ", qid");
+    pprint_int32(pdu, rx, offsetp, ", mode");
+    pprint_int32(pdu, rx, offsetp, ", atime");
+    pprint_int32(pdu, rx, offsetp, ", mtime");
+    pprint_int64(pdu, rx, offsetp, ", length");
+    pprint_str(pdu, rx, offsetp, ", name");
+    pprint_str(pdu, rx, offsetp, ", uid");
+    pprint_str(pdu, rx, offsetp, ", gid");
+    pprint_str(pdu, rx, offsetp, ", muid");
+    pprint_str(pdu, rx, offsetp, ", extension");
+    pprint_int32(pdu, rx, offsetp, ", uid");
+    pprint_int32(pdu, rx, offsetp, ", gid");
+    pprint_int32(pdu, rx, offsetp, ", muid");
+    fprintf(llogfile, "}");
+}
+
+static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp,
+                                                  const char *name)
+{
+    fprintf(llogfile, "%s={", name);
+    pprint_qid(pdu, rx, offsetp, "qid");
+    pprint_int32(pdu, rx, offsetp, ", st_mode");
+    pprint_int64(pdu, rx, offsetp, ", st_nlink");
+    pprint_int32(pdu, rx, offsetp, ", st_uid");
+    pprint_int32(pdu, rx, offsetp, ", st_gid");
+    pprint_int64(pdu, rx, offsetp, ", st_rdev");
+    pprint_int64(pdu, rx, offsetp, ", st_size");
+    pprint_int64(pdu, rx, offsetp, ", st_blksize");
+    pprint_int64(pdu, rx, offsetp, ", st_blocks");
+    pprint_int64(pdu, rx, offsetp, ", atime");
+    pprint_int64(pdu, rx, offsetp, ", atime_nsec");
+    pprint_int64(pdu, rx, offsetp, ", mtime");
+    pprint_int64(pdu, rx, offsetp, ", mtime_nsec");
+    pprint_int64(pdu, rx, offsetp, ", ctime");
+    pprint_int64(pdu, rx, offsetp, ", ctime_nsec");
+    fprintf(llogfile, "}");
+}
+
+
+
+static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    int sg_count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    uint16_t tmp_count, count, i;
+    size_t copied = 0;
+
+    fprintf(llogfile, "%s={", name);
+
+    /* Get the count */
+    copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
+    BUG_ON(copied != sizeof(tmp_count));
+    count = le16_to_cpupu(&tmp_count);
+    offset += copied;
+
+    for (i = 0; i < count; i++) {
+        char str[512];
+        if (i) {
+            fprintf(llogfile, ", ");
+        }
+        snprintf(str, sizeof(str), "[%d]", i);
+        pprint_str(pdu, rx, &offset, str);
+    }
+
+    fprintf(llogfile, "}");
+
+    *offsetp = offset;
+}
+
+static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    int sg_count = get_sg_count(pdu, rx);
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    uint16_t tmp_count, count, i;
+    size_t copied = 0;
+
+    fprintf(llogfile, "%s={", name);
+
+    copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
+    BUG_ON(copied != sizeof(tmp_count));
+    count = le16_to_cpupu(&tmp_count);
+    offset += copied;
+
+    for (i = 0; i < count; i++) {
+        char str[512];
+        if (i) {
+            fprintf(llogfile, ", ");
+        }
+        snprintf(str, sizeof(str), "[%d]", i);
+        pprint_qid(pdu, rx, &offset, str);
+    }
+
+    fprintf(llogfile, "}");
+
+    *offsetp = offset;
+}
+
+static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    struct iovec *sg = get_sg(pdu, rx);
+    unsigned int count;
+    int i;
+
+    if (rx) {
+        count = pdu->elem.in_num;
+    } else {
+        count = pdu->elem.out_num;
+    }
+
+    fprintf(llogfile, "%s={", name);
+    for (i = 0; i < count; i++) {
+        if (i) {
+            fprintf(llogfile, ", ");
+        }
+        fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len);
+    }
+    fprintf(llogfile, "}");
+}
+
+/* FIXME: read from a directory fid returns serialized stat_t's */
+#ifdef DEBUG_DATA
+static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+    struct iovec *sg = get_sg(pdu, rx);
+    size_t offset = *offsetp;
+    unsigned int count;
+    int32_t size;
+    int total, i, j;
+    ssize_t len;
+
+    if (rx) {
+        count = pdu->elem.in_num;
+    } else
+        count = pdu->elem.out_num;
+    }
+
+    BUG_ON((offset + sizeof(size)) > sg[0].iov_len);
+
+    memcpy(&size, sg[0].iov_base + offset, sizeof(size));
+    offset += sizeof(size);
+
+    fprintf(llogfile, "size: %x\n", size);
+
+    sg[0].iov_base += 11; /* skip header */
+    sg[0].iov_len -= 11;
+
+    total = 0;
+    for (i = 0; i < count; i++) {
+        total += sg[i].iov_len;
+        if (total >= size) {
+            /* trim sg list so writev does the right thing */
+            sg[i].iov_len -= (total - size);
+            i++;
+            break;
+        }
+    }
+
+    fprintf(llogfile, "%s={\"", name);
+    fflush(llogfile);
+    for (j = 0; j < i; j++) {
+        if (j) {
+            fprintf(llogfile, "\", \"");
+            fflush(llogfile);
+        }
+
+        do {
+            len = writev(fileno(llogfile), &sg[j], 1);
+        } while (len == -1 && errno == EINTR);
+        fprintf(llogfile, "len == %ld: %m\n", len);
+        BUG_ON(len != sg[j].iov_len);
+    }
+    fprintf(llogfile, "\"}");
+
+    sg[0].iov_base -= 11;
+    sg[0].iov_len += 11;
+
+}
+#endif
+
+void pprint_pdu(V9fsPDU *pdu)
+{
+    size_t offset = 7;
+
+    if (llogfile == NULL) {
+        llogfile = fopen("/tmp/pdu.log", "w");
+    }
+
+    BUG_ON(!llogfile);
+
+    switch (pdu->id) {
+    case P9_TREADDIR:
+        fprintf(llogfile, "TREADDIR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int64(pdu, 0, &offset, ", initial offset");
+        pprint_int32(pdu, 0, &offset, ", max count");
+        break;
+    case P9_RREADDIR:
+        fprintf(llogfile, "RREADDIR: (");
+        pprint_int32(pdu, 1, &offset, "count");
+#ifdef DEBUG_DATA
+        pprint_data(pdu, 1, &offset, ", data");
+#endif
+        break;
+    case P9_TMKDIR:
+        fprintf(llogfile, "TMKDIR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, "name");
+        pprint_int32(pdu, 0, &offset, "mode");
+        pprint_int32(pdu, 0, &offset, "gid");
+        break;
+    case P9_RMKDIR:
+        fprintf(llogfile, "RMKDIR: (");
+        pprint_qid(pdu, 0, &offset, "qid");
+        break;
+    case P9_TVERSION:
+        fprintf(llogfile, "TVERSION: (");
+        pprint_int32(pdu, 0, &offset, "msize");
+        pprint_str(pdu, 0, &offset, ", version");
+        break;
+    case P9_RVERSION:
+        fprintf(llogfile, "RVERSION: (");
+        pprint_int32(pdu, 1, &offset, "msize");
+        pprint_str(pdu, 1, &offset, ", version");
+        break;
+    case P9_TGETATTR:
+        fprintf(llogfile, "TGETATTR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RGETATTR:
+        fprintf(llogfile, "RGETATTR: (");
+        pprint_stat_dotl(pdu, 1, &offset, "getattr");
+        break;
+    case P9_TAUTH:
+        fprintf(llogfile, "TAUTH: (");
+        pprint_int32(pdu, 0, &offset, "afid");
+        pprint_str(pdu, 0, &offset, ", uname");
+        pprint_str(pdu, 0, &offset, ", aname");
+        pprint_int32(pdu, 0, &offset, ", n_uname");
+        break;
+    case P9_RAUTH:
+        fprintf(llogfile, "RAUTH: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        break;
+    case P9_TATTACH:
+        fprintf(llogfile, "TATTACH: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int32(pdu, 0, &offset, ", afid");
+        pprint_str(pdu, 0, &offset, ", uname");
+        pprint_str(pdu, 0, &offset, ", aname");
+        pprint_int32(pdu, 0, &offset, ", n_uname");
+        break;
+    case P9_RATTACH:
+        fprintf(llogfile, "RATTACH: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        break;
+    case P9_TERROR:
+        fprintf(llogfile, "TERROR: (");
+        break;
+    case P9_RERROR:
+        fprintf(llogfile, "RERROR: (");
+        pprint_str(pdu, 1, &offset, "ename");
+        pprint_int32(pdu, 1, &offset, ", ecode");
+        break;
+    case P9_TFLUSH:
+        fprintf(llogfile, "TFLUSH: (");
+        pprint_int16(pdu, 0, &offset, "oldtag");
+        break;
+    case P9_RFLUSH:
+        fprintf(llogfile, "RFLUSH: (");
+        break;
+    case P9_TWALK:
+        fprintf(llogfile, "TWALK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int32(pdu, 0, &offset, ", newfid");
+        pprint_strs(pdu, 0, &offset, ", wnames");
+        break;
+    case P9_RWALK:
+        fprintf(llogfile, "RWALK: (");
+        pprint_qids(pdu, 1, &offset, "wqids");
+        break;
+    case P9_TOPEN:
+        fprintf(llogfile, "TOPEN: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", mode");
+        break;
+    case P9_ROPEN:
+        fprintf(llogfile, "ROPEN: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        pprint_int32(pdu, 1, &offset, ", iounit");
+        break;
+    case P9_TCREATE:
+        fprintf(llogfile, "TCREATE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int32(pdu, 0, &offset, ", perm");
+        pprint_int8(pdu, 0, &offset, ", mode");
+        pprint_str(pdu, 0, &offset, ", extension");
+        break;
+    case P9_RCREATE:
+        fprintf(llogfile, "RCREATE: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        pprint_int32(pdu, 1, &offset, ", iounit");
+        break;
+    case P9_TSYMLINK:
+        fprintf(llogfile, "TSYMLINK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_str(pdu, 0, &offset, ", symname");
+        pprint_int32(pdu, 0, &offset, ", gid");
+        break;
+    case P9_RSYMLINK:
+        fprintf(llogfile, "RSYMLINK: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        break;
+    case P9_TLCREATE:
+        fprintf(llogfile, "TLCREATE: (");
+        pprint_int32(pdu, 0, &offset, "dfid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        pprint_int32(pdu, 0, &offset, ", mode");
+        pprint_int32(pdu, 0, &offset, ", gid");
+        break;
+    case P9_RLCREATE:
+        fprintf(llogfile, "RLCREATE: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        pprint_int32(pdu, 1, &offset, ", iounit");
+        break;
+    case P9_TMKNOD:
+       fprintf(llogfile, "TMKNOD: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, "name");
+        pprint_int32(pdu, 0, &offset, "mode");
+        pprint_int32(pdu, 0, &offset, "major");
+        pprint_int32(pdu, 0, &offset, "minor");
+        pprint_int32(pdu, 0, &offset, "gid");
+        break;
+    case P9_RMKNOD:
+        fprintf(llogfile, "RMKNOD: )");
+        pprint_qid(pdu, 0, &offset, "qid");
+        break;
+    case P9_TREADLINK:
+       fprintf(llogfile, "TREADLINK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RREADLINK:
+       fprintf(llogfile, "RREADLINK: (");
+        pprint_str(pdu, 0, &offset, "target");
+        break;
+    case P9_TREAD:
+        fprintf(llogfile, "TREAD: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int64(pdu, 0, &offset, ", offset");
+        pprint_int32(pdu, 0, &offset, ", count");
+        pprint_sg(pdu, 0, &offset, ", sg");
+        break;
+    case P9_RREAD:
+        fprintf(llogfile, "RREAD: (");
+        pprint_int32(pdu, 1, &offset, "count");
+        pprint_sg(pdu, 1, &offset, ", sg");
+        offset = 7;
+#ifdef DEBUG_DATA
+        pprint_data(pdu, 1, &offset, ", data");
+#endif
+        break;
+    case P9_TWRITE:
+        fprintf(llogfile, "TWRITE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int64(pdu, 0, &offset, ", offset");
+        pprint_int32(pdu, 0, &offset, ", count");
+        break;
+    case P9_RWRITE:
+        fprintf(llogfile, "RWRITE: (");
+        pprint_int32(pdu, 1, &offset, "count");
+        break;
+    case P9_TCLUNK:
+        fprintf(llogfile, "TCLUNK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RCLUNK:
+        fprintf(llogfile, "RCLUNK: (");
+        break;
+    case P9_TFSYNC:
+        fprintf(llogfile, "TFSYNC: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RFSYNC:
+        fprintf(llogfile, "RFSYNC: (");
+        break;
+    case P9_TLINK:
+        fprintf(llogfile, "TLINK: (");
+        pprint_int32(pdu, 0, &offset, "dfid");
+        pprint_int32(pdu, 0, &offset, ", fid");
+        pprint_str(pdu, 0, &offset, ", newpath");
+        break;
+    case P9_RLINK:
+        fprintf(llogfile, "RLINK: (");
+        break;
+    case P9_TREMOVE:
+        fprintf(llogfile, "TREMOVE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RREMOVE:
+        fprintf(llogfile, "RREMOVE: (");
+        break;
+    case P9_TSTAT:
+        fprintf(llogfile, "TSTAT: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RSTAT:
+        fprintf(llogfile, "RSTAT: (");
+        offset += 2; /* ignored */
+        pprint_stat(pdu, 1, &offset, "stat");
+        break;
+    case P9_TWSTAT:
+        fprintf(llogfile, "TWSTAT: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        offset += 2; /* ignored */
+        pprint_stat(pdu, 0, &offset, ", stat");
+        break;
+    case P9_RWSTAT:
+        fprintf(llogfile, "RWSTAT: (");
+        break;
+    case P9_TXATTRWALK:
+        fprintf(llogfile, "TXATTRWALK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int32(pdu, 0, &offset, ", newfid");
+        pprint_str(pdu, 0, &offset, ", xattr name");
+        break;
+    case P9_RXATTRWALK:
+        fprintf(llogfile, "RXATTRWALK: (");
+        pprint_int64(pdu, 1, &offset, "xattrsize");
+    case P9_TXATTRCREATE:
+        fprintf(llogfile, "TXATTRCREATE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int64(pdu, 0, &offset, ", xattrsize");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        break;
+    case P9_RXATTRCREATE:
+        fprintf(llogfile, "RXATTRCREATE: (");
+        break;
+    case P9_TLOCK:
+        fprintf(llogfile, "TLOCK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", type");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    case P9_RLOCK:
+        fprintf(llogfile, "RLOCK: (");
+        pprint_int8(pdu, 0, &offset, "status");
+        break;
+    case P9_TGETLOCK:
+        fprintf(llogfile, "TGETLOCK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", type");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    case P9_RGETLOCK:
+        fprintf(llogfile, "RGETLOCK: (");
+        pprint_int8(pdu, 0, &offset, "type");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    default:
+        fprintf(llogfile, "unknown(%d): (", pdu->id);
+        break;
+    }
+
+    fprintf(llogfile, ")\n");
+    /* Flush the log message out */
+    fflush(llogfile);
+}
diff --git a/hw/9pfs/virtio-9p-debug.h b/hw/9pfs/virtio-9p-debug.h
new file mode 100644 (file)
index 0000000..d9a2491
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _QEMU_VIRTIO_9P_DEBUG_H
+#define _QEMU_VIRTIO_9P_DEBUG_H
+
+void pprint_pdu(V9fsPDU *pdu);
+
+#endif
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
new file mode 100644 (file)
index 0000000..0a015de
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * Virtio 9p Posix callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <attr/xattr.h>
+
+
+static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
+{
+    int err;
+    err =  lstat(rpath(fs_ctx, path), stbuf);
+    if (err) {
+        return err;
+    }
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        /* Actual credentials are part of extended attrs */
+        uid_t tmp_uid;
+        gid_t tmp_gid;
+        mode_t tmp_mode;
+        dev_t tmp_dev;
+        if (getxattr(rpath(fs_ctx, path), "user.virtfs.uid", &tmp_uid,
+                    sizeof(uid_t)) > 0) {
+            stbuf->st_uid = tmp_uid;
+        }
+        if (getxattr(rpath(fs_ctx, path), "user.virtfs.gid", &tmp_gid,
+                    sizeof(gid_t)) > 0) {
+            stbuf->st_gid = tmp_gid;
+        }
+        if (getxattr(rpath(fs_ctx, path), "user.virtfs.mode", &tmp_mode,
+                    sizeof(mode_t)) > 0) {
+            stbuf->st_mode = tmp_mode;
+        }
+        if (getxattr(rpath(fs_ctx, path), "user.virtfs.rdev", &tmp_dev,
+                        sizeof(dev_t)) > 0) {
+                stbuf->st_rdev = tmp_dev;
+        }
+    }
+    return err;
+}
+
+static int local_set_xattr(const char *path, FsCred *credp)
+{
+    int err;
+    if (credp->fc_uid != -1) {
+        err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
+                0);
+        if (err) {
+            return err;
+        }
+    }
+    if (credp->fc_gid != -1) {
+        err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
+                0);
+        if (err) {
+            return err;
+        }
+    }
+    if (credp->fc_mode != -1) {
+        err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
+                sizeof(mode_t), 0);
+        if (err) {
+            return err;
+        }
+    }
+    if (credp->fc_rdev != -1) {
+        err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
+                sizeof(dev_t), 0);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
+}
+
+static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
+        FsCred *credp)
+{
+    if (chmod(rpath(fs_ctx, path), credp->fc_mode & 07777) < 0) {
+        return -1;
+    }
+    if (lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
+        /*
+         * If we fail to change ownership and if we are
+         * using security model none. Ignore the error
+         */
+        if (fs_ctx->fs_sm != SM_NONE) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
+        char *buf, size_t bufsz)
+{
+    ssize_t tsize = -1;
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        int fd;
+        fd = open(rpath(fs_ctx, path), O_RDONLY);
+        if (fd == -1) {
+            return -1;
+        }
+        do {
+            tsize = read(fd, (void *)buf, bufsz);
+        } while (tsize == -1 && errno == EINTR);
+        close(fd);
+        return tsize;
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
+    }
+    return tsize;
+}
+
+static int local_close(FsContext *ctx, int fd)
+{
+    return close(fd);
+}
+
+static int local_closedir(FsContext *ctx, DIR *dir)
+{
+    return closedir(dir);
+}
+
+static int local_open(FsContext *ctx, const char *path, int flags)
+{
+    return open(rpath(ctx, path), flags);
+}
+
+static DIR *local_opendir(FsContext *ctx, const char *path)
+{
+    return opendir(rpath(ctx, path));
+}
+
+static void local_rewinddir(FsContext *ctx, DIR *dir)
+{
+    return rewinddir(dir);
+}
+
+static off_t local_telldir(FsContext *ctx, DIR *dir)
+{
+    return telldir(dir);
+}
+
+static struct dirent *local_readdir(FsContext *ctx, DIR *dir)
+{
+    return readdir(dir);
+}
+
+static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
+{
+    return seekdir(dir, off);
+}
+
+static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+                            int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return preadv(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return readv(fd, iov, iovcnt);
+    }
+#endif
+}
+
+static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+                            int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return pwritev(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return writev(fd, iov, iovcnt);
+    }
+#endif
+}
+
+static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        return local_set_xattr(rpath(fs_ctx, path), credp);
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        return chmod(rpath(fs_ctx, path), credp->fc_mode);
+    }
+    return -1;
+}
+
+static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    int err = -1;
+    int serrno = 0;
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        err = mknod(rpath(fs_ctx, path), SM_LOCAL_MODE_BITS|S_IFREG, 0);
+        if (err == -1) {
+            return err;
+        }
+        local_set_xattr(rpath(fs_ctx, path), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
+        if (err == -1) {
+            return err;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    return err;
+
+err_end:
+    remove(rpath(fs_ctx, path));
+    errno = serrno;
+    return err;
+}
+
+static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    int err = -1;
+    int serrno = 0;
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        err = mkdir(rpath(fs_ctx, path), SM_LOCAL_DIR_MODE_BITS);
+        if (err == -1) {
+            return err;
+        }
+        credp->fc_mode = credp->fc_mode|S_IFDIR;
+        err = local_set_xattr(rpath(fs_ctx, path), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
+        if (err == -1) {
+            return err;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    return err;
+
+err_end:
+    remove(rpath(fs_ctx, path));
+    errno = serrno;
+    return err;
+}
+
+static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+{
+    int err;
+    err = fstat(fd, stbuf);
+    if (err) {
+        return err;
+    }
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        /* Actual credentials are part of extended attrs */
+        uid_t tmp_uid;
+        gid_t tmp_gid;
+        mode_t tmp_mode;
+        dev_t tmp_dev;
+
+        if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
+            stbuf->st_uid = tmp_uid;
+        }
+        if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
+            stbuf->st_gid = tmp_gid;
+        }
+        if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
+            stbuf->st_mode = tmp_mode;
+        }
+        if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
+                stbuf->st_rdev = tmp_dev;
+        }
+    }
+    return err;
+}
+
+static int local_open2(FsContext *fs_ctx, const char *path, int flags,
+        FsCred *credp)
+{
+    int fd = -1;
+    int err = -1;
+    int serrno = 0;
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        fd = open(rpath(fs_ctx, path), flags, SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            return fd;
+        }
+        credp->fc_mode = credp->fc_mode|S_IFREG;
+        /* Set cleint credentials in xattr */
+        err = local_set_xattr(rpath(fs_ctx, path), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
+        if (fd == -1) {
+            return fd;
+        }
+        err = local_post_create_passthrough(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    return fd;
+
+err_end:
+    close(fd);
+    remove(rpath(fs_ctx, path));
+    errno = serrno;
+    return err;
+}
+
+
+static int local_symlink(FsContext *fs_ctx, const char *oldpath,
+        const char *newpath, FsCred *credp)
+{
+    int err = -1;
+    int serrno = 0;
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        int fd;
+        ssize_t oldpath_size, write_size;
+        fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
+                SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            return fd;
+        }
+        /* Write the oldpath (target) to the file. */
+        oldpath_size = strlen(oldpath);
+        do {
+            write_size = write(fd, (void *)oldpath, oldpath_size);
+        } while (write_size == -1 && errno == EINTR);
+
+        if (write_size != oldpath_size) {
+            serrno = errno;
+            close(fd);
+            err = -1;
+            goto err_end;
+        }
+        close(fd);
+        /* Set cleint credentials in symlink's xattr */
+        credp->fc_mode = credp->fc_mode|S_IFLNK;
+        err = local_set_xattr(rpath(fs_ctx, newpath), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        err = symlink(oldpath, rpath(fs_ctx, newpath));
+        if (err) {
+            return err;
+        }
+        err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
+        if (err == -1) {
+            /*
+             * If we fail to change ownership and if we are
+             * using security model none. Ignore the error
+             */
+            if (fs_ctx->fs_sm != SM_NONE) {
+                serrno = errno;
+                goto err_end;
+            } else
+                err = 0;
+        }
+    }
+    return err;
+
+err_end:
+    remove(rpath(fs_ctx, newpath));
+    errno = serrno;
+    return err;
+}
+
+static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
+{
+    char *tmp = qemu_strdup(rpath(ctx, oldpath));
+    int err, serrno = 0;
+
+    if (tmp == NULL) {
+        return -ENOMEM;
+    }
+
+    err = link(tmp, rpath(ctx, newpath));
+    if (err == -1) {
+        serrno = errno;
+    }
+
+    qemu_free(tmp);
+
+    if (err == -1) {
+        errno = serrno;
+    }
+
+    return err;
+}
+
+static int local_truncate(FsContext *ctx, const char *path, off_t size)
+{
+    return truncate(rpath(ctx, path), size);
+}
+
+static int local_rename(FsContext *ctx, const char *oldpath,
+                        const char *newpath)
+{
+    char *tmp;
+    int err;
+
+    tmp = qemu_strdup(rpath(ctx, oldpath));
+
+    err = rename(tmp, rpath(ctx, newpath));
+    if (err == -1) {
+        int serrno = errno;
+        qemu_free(tmp);
+        errno = serrno;
+    } else {
+        qemu_free(tmp);
+    }
+
+    return err;
+
+}
+
+static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
+            (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
+        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
+    } else if (fs_ctx->fs_sm == SM_MAPPED) {
+        return local_set_xattr(rpath(fs_ctx, path), credp);
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
+        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
+    }
+    return -1;
+}
+
+static int local_utimensat(FsContext *s, const char *path,
+                           const struct timespec *buf)
+{
+    return qemu_utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
+}
+
+static int local_remove(FsContext *ctx, const char *path)
+{
+    return remove(rpath(ctx, path));
+}
+
+static int local_fsync(FsContext *ctx, int fd, int datasync)
+{
+    if (datasync) {
+        return qemu_fdatasync(fd);
+    } else {
+        return fsync(fd);
+    }
+}
+
+static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
+{
+   return statfs(rpath(s, path), stbuf);
+}
+
+static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
+                               const char *name, void *value, size_t size)
+{
+    return v9fs_get_xattr(ctx, path, name, value, size);
+}
+
+static ssize_t local_llistxattr(FsContext *ctx, const char *path,
+                                void *value, size_t size)
+{
+    return v9fs_list_xattr(ctx, path, value, size);
+}
+
+static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
+                           void *value, size_t size, int flags)
+{
+    return v9fs_set_xattr(ctx, path, name, value, size, flags);
+}
+
+static int local_lremovexattr(FsContext *ctx,
+                              const char *path, const char *name)
+{
+    return v9fs_remove_xattr(ctx, path, name);
+}
+
+
+FileOperations local_ops = {
+    .lstat = local_lstat,
+    .readlink = local_readlink,
+    .close = local_close,
+    .closedir = local_closedir,
+    .open = local_open,
+    .opendir = local_opendir,
+    .rewinddir = local_rewinddir,
+    .telldir = local_telldir,
+    .readdir = local_readdir,
+    .seekdir = local_seekdir,
+    .preadv = local_preadv,
+    .pwritev = local_pwritev,
+    .chmod = local_chmod,
+    .mknod = local_mknod,
+    .mkdir = local_mkdir,
+    .fstat = local_fstat,
+    .open2 = local_open2,
+    .symlink = local_symlink,
+    .link = local_link,
+    .truncate = local_truncate,
+    .rename = local_rename,
+    .chown = local_chown,
+    .utimensat = local_utimensat,
+    .remove = local_remove,
+    .fsync = local_fsync,
+    .statfs = local_statfs,
+    .lgetxattr = local_lgetxattr,
+    .llistxattr = local_llistxattr,
+    .lsetxattr = local_lsetxattr,
+    .lremovexattr = local_lremovexattr,
+};
diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c
new file mode 100644 (file)
index 0000000..575abe8
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Virtio 9p system.posix* xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <attr/xattr.h>
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "fsdev/file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+#define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access"
+#define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default"
+#define ACL_ACCESS "system.posix_acl_access"
+#define ACL_DEFAULT "system.posix_acl_default"
+
+static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size);
+}
+
+static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t osize)
+{
+    ssize_t len = sizeof(ACL_ACCESS);
+
+    if (!value) {
+        return len;
+    }
+
+    if (osize < len) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, ACL_ACCESS, len);
+    return 0;
+}
+
+static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size, flags);
+}
+
+static int mp_pacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    int ret;
+    ret  = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS);
+    if (ret == -1 && errno == ENODATA) {
+        /*
+         * We don't get ENODATA error when trying to remove a
+         * posix acl that is not present. So don't throw the error
+         * even in case of mapped security model
+         */
+        errno = 0;
+        ret = 0;
+    }
+    return ret;
+}
+
+static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size);
+}
+
+static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t osize)
+{
+    ssize_t len = sizeof(ACL_DEFAULT);
+
+    if (!value) {
+        return len;
+    }
+
+    if (osize < len) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, ACL_DEFAULT, len);
+    return 0;
+}
+
+static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size, flags);
+}
+
+static int mp_dacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    int ret;
+    ret  = lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
+    if (ret == -1 && errno == ENODATA) {
+        /*
+         * We don't get ENODATA error when trying to remove a
+         * posix acl that is not present. So don't throw the error
+         * even in case of mapped security model
+         */
+        errno = 0;
+        ret = 0;
+    }
+    return ret;
+}
+
+
+XattrOperations mapped_pacl_xattr = {
+    .name = "system.posix_acl_access",
+    .getxattr = mp_pacl_getxattr,
+    .setxattr = mp_pacl_setxattr,
+    .listxattr = mp_pacl_listxattr,
+    .removexattr = mp_pacl_removexattr,
+};
+
+XattrOperations mapped_dacl_xattr = {
+    .name = "system.posix_acl_default",
+    .getxattr = mp_dacl_getxattr,
+    .setxattr = mp_dacl_setxattr,
+    .listxattr = mp_dacl_listxattr,
+    .removexattr = mp_dacl_removexattr,
+};
+
+XattrOperations passthrough_acl_xattr = {
+    .name = "system.posix_acl_",
+    .getxattr = pt_getxattr,
+    .setxattr = pt_setxattr,
+    .listxattr = pt_listxattr,
+    .removexattr = pt_removexattr,
+};
+
+XattrOperations none_acl_xattr = {
+    .name = "system.posix_acl_",
+    .getxattr = notsup_getxattr,
+    .setxattr = notsup_setxattr,
+    .listxattr = notsup_listxattr,
+    .removexattr = notsup_removexattr,
+};
diff --git a/hw/9pfs/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c
new file mode 100644 (file)
index 0000000..bba13ce
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Virtio 9p user. xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "fsdev/file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = ENOATTR;
+        return -1;
+    }
+    return lgetxattr(rpath(ctx, path), name, value, size);
+}
+
+static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t size)
+{
+    int name_size = strlen(name) + 1;
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+
+        /*  check if it is a mapped posix acl */
+        if (strncmp(name, "user.virtfs.system.posix_acl_", 29) == 0) {
+            /* adjust the name and size */
+            name += 12;
+            name_size -= 12;
+        } else {
+            /*
+             * Don't allow fetch of user.virtfs namesapce
+             * in case of mapped security
+             */
+            return 0;
+        }
+    }
+    if (!value) {
+        return name_size;
+    }
+
+    if (size < name_size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, name, name_size);
+    return name_size;
+}
+
+static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = EACCES;
+        return -1;
+    }
+    return lsetxattr(rpath(ctx, path), name, value, size, flags);
+}
+
+static int mp_user_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = EACCES;
+        return -1;
+    }
+    return lremovexattr(rpath(ctx, path), name);
+}
+
+XattrOperations mapped_user_xattr = {
+    .name = "user.",
+    .getxattr = mp_user_getxattr,
+    .setxattr = mp_user_setxattr,
+    .listxattr = mp_user_listxattr,
+    .removexattr = mp_user_removexattr,
+};
+
+XattrOperations passthrough_user_xattr = {
+    .name = "user.",
+    .getxattr = pt_getxattr,
+    .setxattr = pt_setxattr,
+    .listxattr = pt_listxattr,
+    .removexattr = pt_removexattr,
+};
diff --git a/hw/9pfs/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c
new file mode 100644 (file)
index 0000000..03c3d3f
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Virtio 9p  xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "fsdev/file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static XattrOperations *get_xattr_operations(XattrOperations **h,
+                                             const char *name)
+{
+    XattrOperations *xops;
+    for (xops = *(h)++; xops != NULL; xops = *(h)++) {
+        if (!strncmp(name, xops->name, strlen(xops->name))) {
+            return xops;
+        }
+    }
+    return NULL;
+}
+
+ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
+                       const char *name, void *value, size_t size)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->getxattr(ctx, path, name, value, size);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+}
+
+ssize_t pt_listxattr(FsContext *ctx, const char *path,
+                     char *name, void *value, size_t size)
+{
+    int name_size = strlen(name) + 1;
+    if (!value) {
+        return name_size;
+    }
+
+    if (size < name_size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, name, name_size);
+    return name_size;
+}
+
+
+/*
+ * Get the list and pass to each layer to find out whether
+ * to send the data or not
+ */
+ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
+                        void *value, size_t vsize)
+{
+    ssize_t size = 0;
+    void *ovalue = value;
+    XattrOperations *xops;
+    char *orig_value, *orig_value_start;
+    ssize_t xattr_len, parsed_len = 0, attr_len;
+
+    /* Get the actual len */
+    xattr_len = llistxattr(rpath(ctx, path), value, 0);
+    if (xattr_len <= 0) {
+        return xattr_len;
+    }
+
+    /* Now fetch the xattr and find the actual size */
+    orig_value = qemu_malloc(xattr_len);
+    xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
+
+    /* store the orig pointer */
+    orig_value_start = orig_value;
+    while (xattr_len > parsed_len) {
+        xops = get_xattr_operations(ctx->xops, orig_value);
+        if (!xops) {
+            goto next_entry;
+        }
+
+        if (!value) {
+            size += xops->listxattr(ctx, path, orig_value, value, vsize);
+        } else {
+            size = xops->listxattr(ctx, path, orig_value, value, vsize);
+            if (size < 0) {
+                goto err_out;
+            }
+            value += size;
+            vsize -= size;
+        }
+next_entry:
+        /* Got the next entry */
+        attr_len = strlen(orig_value) + 1;
+        parsed_len += attr_len;
+        orig_value += attr_len;
+    }
+    if (value) {
+        size = value - ovalue;
+    }
+
+err_out:
+    qemu_free(orig_value_start);
+    return size;
+}
+
+int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+                   void *value, size_t size, int flags)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->setxattr(ctx, path, name, value, size, flags);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+
+}
+
+int v9fs_remove_xattr(FsContext *ctx,
+                      const char *path, const char *name)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->removexattr(ctx, path, name);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+
+}
+
+XattrOperations *mapped_xattr_ops[] = {
+    &mapped_user_xattr,
+    &mapped_pacl_xattr,
+    &mapped_dacl_xattr,
+    NULL,
+};
+
+XattrOperations *passthrough_xattr_ops[] = {
+    &passthrough_user_xattr,
+    &passthrough_acl_xattr,
+    NULL,
+};
+
+/* for .user none model should be same as passthrough */
+XattrOperations *none_xattr_ops[] = {
+    &passthrough_user_xattr,
+    &none_acl_xattr,
+    NULL,
+};
diff --git a/hw/9pfs/virtio-9p-xattr.h b/hw/9pfs/virtio-9p-xattr.h
new file mode 100644 (file)
index 0000000..2bbae2d
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef _QEMU_VIRTIO_9P_XATTR_H
+#define _QEMU_VIRTIO_9P_XATTR_H
+
+#include <attr/xattr.h>
+
+typedef struct xattr_operations
+{
+    const char *name;
+    ssize_t (*getxattr)(FsContext *ctx, const char *path,
+                        const char *name, void *value, size_t size);
+    ssize_t (*listxattr)(FsContext *ctx, const char *path,
+                         char *name, void *value, size_t size);
+    int (*setxattr)(FsContext *ctx, const char *path, const char *name,
+                    void *value, size_t size, int flags);
+    int (*removexattr)(FsContext *ctx,
+                       const char *path, const char *name);
+} XattrOperations;
+
+
+extern XattrOperations mapped_user_xattr;
+extern XattrOperations passthrough_user_xattr;
+
+extern XattrOperations mapped_pacl_xattr;
+extern XattrOperations mapped_dacl_xattr;
+extern XattrOperations passthrough_acl_xattr;
+extern XattrOperations none_acl_xattr;
+
+extern XattrOperations *mapped_xattr_ops[];
+extern XattrOperations *passthrough_xattr_ops[];
+extern XattrOperations *none_xattr_ops[];
+
+ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, const char *name,
+                       void *value, size_t size);
+ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value,
+                        size_t vsize);
+int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+                          void *value, size_t size, int flags);
+int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
+ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
+                     size_t size);
+
+static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
+                                  const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), name, value, size);
+}
+
+static inline int pt_setxattr(FsContext *ctx, const char *path,
+                              const char *name, void *value,
+                              size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), name, value, size, flags);
+}
+
+static inline int pt_removexattr(FsContext *ctx,
+                                 const char *path, const char *name)
+{
+    return lremovexattr(rpath(ctx, path), name);
+}
+
+static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
+                                      const char *name, void *value,
+                                      size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static inline int notsup_setxattr(FsContext *ctx, const char *path,
+                                  const char *name, void *value,
+                                  size_t size, int flags)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
+                                       char *name, void *value, size_t size)
+{
+    return 0;
+}
+
+static inline int notsup_removexattr(FsContext *ctx,
+                                     const char *path, const char *name)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+#endif
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
new file mode 100644 (file)
index 0000000..b5fc52b
--- /dev/null
@@ -0,0 +1,3747 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "pc.h"
+#include "qemu_socket.h"
+#include "virtio-9p.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-debug.h"
+#include "virtio-9p-xattr.h"
+
+int debug_9p_pdu;
+
+enum {
+    Oread   = 0x00,
+    Owrite  = 0x01,
+    Ordwr   = 0x02,
+    Oexec   = 0x03,
+    Oexcl   = 0x04,
+    Otrunc  = 0x10,
+    Orexec  = 0x20,
+    Orclose = 0x40,
+    Oappend = 0x80,
+};
+
+static int omode_to_uflags(int8_t mode)
+{
+    int ret = 0;
+
+    switch (mode & 3) {
+    case Oread:
+        ret = O_RDONLY;
+        break;
+    case Ordwr:
+        ret = O_RDWR;
+        break;
+    case Owrite:
+        ret = O_WRONLY;
+        break;
+    case Oexec:
+        ret = O_RDONLY;
+        break;
+    }
+
+    if (mode & Otrunc) {
+        ret |= O_TRUNC;
+    }
+
+    if (mode & Oappend) {
+        ret |= O_APPEND;
+    }
+
+    if (mode & Oexcl) {
+        ret |= O_EXCL;
+    }
+
+    return ret;
+}
+
+void cred_init(FsCred *credp)
+{
+    credp->fc_uid = -1;
+    credp->fc_gid = -1;
+    credp->fc_mode = -1;
+    credp->fc_rdev = -1;
+}
+
+static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
+{
+    return s->ops->lstat(&s->ctx, path->data, stbuf);
+}
+
+static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
+{
+    ssize_t len;
+
+    buf->data = qemu_malloc(1024);
+
+    len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
+    if (len > -1) {
+        buf->size = len;
+        buf->data[len] = 0;
+    }
+
+    return len;
+}
+
+static int v9fs_do_close(V9fsState *s, int fd)
+{
+    return s->ops->close(&s->ctx, fd);
+}
+
+static int v9fs_do_closedir(V9fsState *s, DIR *dir)
+{
+    return s->ops->closedir(&s->ctx, dir);
+}
+
+static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
+{
+    return s->ops->open(&s->ctx, path->data, flags);
+}
+
+static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
+{
+    return s->ops->opendir(&s->ctx, path->data);
+}
+
+static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
+{
+    return s->ops->rewinddir(&s->ctx, dir);
+}
+
+static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
+{
+    return s->ops->telldir(&s->ctx, dir);
+}
+
+static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
+{
+    return s->ops->readdir(&s->ctx, dir);
+}
+
+static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
+{
+    return s->ops->seekdir(&s->ctx, dir, off);
+}
+
+static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
+                            int iovcnt, int64_t offset)
+{
+    return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
+}
+
+static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
+                       int iovcnt, int64_t offset)
+{
+    return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
+}
+
+static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
+{
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_mode = mode;
+    return s->ops->chmod(&s->ctx, path->data, &cred);
+}
+
+static int v9fs_do_mknod(V9fsState *s, char *name,
+        mode_t mode, dev_t dev, uid_t uid, gid_t gid)
+{
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = mode;
+    cred.fc_rdev = dev;
+    return s->ops->mknod(&s->ctx, name, &cred);
+}
+
+static int v9fs_do_mkdir(V9fsState *s, char *name, mode_t mode,
+                uid_t uid, gid_t gid)
+{
+    FsCred cred;
+
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = mode;
+
+    return s->ops->mkdir(&s->ctx, name, &cred);
+}
+
+static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
+{
+    return s->ops->fstat(&s->ctx, fd, stbuf);
+}
+
+static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
+        int flags, int mode)
+{
+    FsCred cred;
+
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = mode & 07777;
+    flags = flags;
+
+    return s->ops->open2(&s->ctx, fullname, flags, &cred);
+}
+
+static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
+        const char *oldpath, const char *newpath, gid_t gid)
+{
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_uid = fidp->uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = 0777;
+
+    return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
+}
+
+static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+{
+    return s->ops->link(&s->ctx, oldpath->data, newpath->data);
+}
+
+static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
+{
+    return s->ops->truncate(&s->ctx, path->data, size);
+}
+
+static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
+                            V9fsString *newpath)
+{
+    return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
+}
+
+static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
+{
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+
+    return s->ops->chown(&s->ctx, path->data, &cred);
+}
+
+static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
+                                           const struct timespec times[2])
+{
+    return s->ops->utimensat(&s->ctx, path->data, times);
+}
+
+static int v9fs_do_remove(V9fsState *s, V9fsString *path)
+{
+    return s->ops->remove(&s->ctx, path->data);
+}
+
+static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
+{
+    return s->ops->fsync(&s->ctx, fd, datasync);
+}
+
+static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
+{
+    return s->ops->statfs(&s->ctx, path->data, stbuf);
+}
+
+static ssize_t v9fs_do_lgetxattr(V9fsState *s, V9fsString *path,
+                             V9fsString *xattr_name,
+                             void *value, size_t size)
+{
+    return s->ops->lgetxattr(&s->ctx, path->data,
+                             xattr_name->data, value, size);
+}
+
+static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
+                              void *value, size_t size)
+{
+    return s->ops->llistxattr(&s->ctx, path->data,
+                              value, size);
+}
+
+static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
+                             V9fsString *xattr_name,
+                             void *value, size_t size, int flags)
+{
+    return s->ops->lsetxattr(&s->ctx, path->data,
+                             xattr_name->data, value, size, flags);
+}
+
+static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
+                                V9fsString *xattr_name)
+{
+    return s->ops->lremovexattr(&s->ctx, path->data,
+                                xattr_name->data);
+}
+
+
+static void v9fs_string_init(V9fsString *str)
+{
+    str->data = NULL;
+    str->size = 0;
+}
+
+static void v9fs_string_free(V9fsString *str)
+{
+    qemu_free(str->data);
+    str->data = NULL;
+    str->size = 0;
+}
+
+static void v9fs_string_null(V9fsString *str)
+{
+    v9fs_string_free(str);
+}
+
+static int number_to_string(void *arg, char type)
+{
+    unsigned int ret = 0;
+
+    switch (type) {
+    case 'u': {
+        unsigned int num = *(unsigned int *)arg;
+
+        do {
+            ret++;
+            num = num/10;
+        } while (num);
+        break;
+    }
+    case 'U': {
+        unsigned long num = *(unsigned long *)arg;
+        do {
+            ret++;
+            num = num/10;
+        } while (num);
+        break;
+    }
+    default:
+        printf("Number_to_string: Unknown number format\n");
+        return -1;
+    }
+
+    return ret;
+}
+
+static int GCC_FMT_ATTR(2, 0)
+v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
+{
+    va_list ap2;
+    char *iter = (char *)fmt;
+    int len = 0;
+    int nr_args = 0;
+    char *arg_char_ptr;
+    unsigned int arg_uint;
+    unsigned long arg_ulong;
+
+    /* Find the number of %'s that denotes an argument */
+    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
+        nr_args++;
+        iter++;
+    }
+
+    len = strlen(fmt) - 2*nr_args;
+
+    if (!nr_args) {
+        goto alloc_print;
+    }
+
+    va_copy(ap2, ap);
+
+    iter = (char *)fmt;
+
+    /* Now parse the format string */
+    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
+        iter++;
+        switch (*iter) {
+        case 'u':
+            arg_uint = va_arg(ap2, unsigned int);
+            len += number_to_string((void *)&arg_uint, 'u');
+            break;
+        case 'l':
+            if (*++iter == 'u') {
+                arg_ulong = va_arg(ap2, unsigned long);
+                len += number_to_string((void *)&arg_ulong, 'U');
+            } else {
+                return -1;
+            }
+            break;
+        case 's':
+            arg_char_ptr = va_arg(ap2, char *);
+            len += strlen(arg_char_ptr);
+            break;
+        case 'c':
+            len += 1;
+            break;
+        default:
+            fprintf(stderr,
+                   "v9fs_string_alloc_printf:Incorrect format %c", *iter);
+            return -1;
+        }
+        iter++;
+    }
+
+alloc_print:
+    *strp = qemu_malloc((len + 1) * sizeof(**strp));
+
+    return vsprintf(*strp, fmt, ap);
+}
+
+static void GCC_FMT_ATTR(2, 3)
+v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
+{
+    va_list ap;
+    int err;
+
+    v9fs_string_free(str);
+
+    va_start(ap, fmt);
+    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
+    BUG_ON(err == -1);
+    va_end(ap);
+
+    str->size = err;
+}
+
+static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
+{
+    v9fs_string_free(lhs);
+    v9fs_string_sprintf(lhs, "%s", rhs->data);
+}
+
+static size_t v9fs_string_size(V9fsString *str)
+{
+    return str->size;
+}
+
+static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
+{
+    V9fsFidState *f;
+
+    for (f = s->fid_list; f; f = f->next) {
+        if (f->fid == fid) {
+            return f;
+        }
+    }
+
+    return NULL;
+}
+
+static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
+{
+    V9fsFidState *f;
+
+    f = lookup_fid(s, fid);
+    if (f) {
+        return NULL;
+    }
+
+    f = qemu_mallocz(sizeof(V9fsFidState));
+
+    f->fid = fid;
+    f->fid_type = P9_FID_NONE;
+
+    f->next = s->fid_list;
+    s->fid_list = f;
+
+    return f;
+}
+
+static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
+{
+    int retval = 0;
+
+    if (fidp->fs.xattr.copied_len == -1) {
+        /* getxattr/listxattr fid */
+        goto free_value;
+    }
+    /*
+     * if this is fid for setxattr. clunk should
+     * result in setxattr localcall
+     */
+    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
+        /* clunk after partial write */
+        retval = -EINVAL;
+        goto free_out;
+    }
+    if (fidp->fs.xattr.len) {
+        retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
+                                   fidp->fs.xattr.value,
+                                   fidp->fs.xattr.len,
+                                   fidp->fs.xattr.flags);
+    } else {
+        retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
+    }
+free_out:
+    v9fs_string_free(&fidp->fs.xattr.name);
+free_value:
+    if (fidp->fs.xattr.value) {
+        qemu_free(fidp->fs.xattr.value);
+    }
+    return retval;
+}
+
+static int free_fid(V9fsState *s, int32_t fid)
+{
+    int retval = 0;
+    V9fsFidState **fidpp, *fidp;
+
+    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
+        if ((*fidpp)->fid == fid) {
+            break;
+        }
+    }
+
+    if (*fidpp == NULL) {
+        return -ENOENT;
+    }
+
+    fidp = *fidpp;
+    *fidpp = fidp->next;
+
+    if (fidp->fid_type == P9_FID_FILE) {
+        v9fs_do_close(s, fidp->fs.fd);
+    } else if (fidp->fid_type == P9_FID_DIR) {
+        v9fs_do_closedir(s, fidp->fs.dir);
+    } else if (fidp->fid_type == P9_FID_XATTR) {
+        retval = v9fs_xattr_fid_clunk(s, fidp);
+    }
+    v9fs_string_free(&fidp->path);
+    qemu_free(fidp);
+
+    return retval;
+}
+
+#define P9_QID_TYPE_DIR         0x80
+#define P9_QID_TYPE_SYMLINK     0x02
+
+#define P9_STAT_MODE_DIR        0x80000000
+#define P9_STAT_MODE_APPEND     0x40000000
+#define P9_STAT_MODE_EXCL       0x20000000
+#define P9_STAT_MODE_MOUNT      0x10000000
+#define P9_STAT_MODE_AUTH       0x08000000
+#define P9_STAT_MODE_TMP        0x04000000
+#define P9_STAT_MODE_SYMLINK    0x02000000
+#define P9_STAT_MODE_LINK       0x01000000
+#define P9_STAT_MODE_DEVICE     0x00800000
+#define P9_STAT_MODE_NAMED_PIPE 0x00200000
+#define P9_STAT_MODE_SOCKET     0x00100000
+#define P9_STAT_MODE_SETUID     0x00080000
+#define P9_STAT_MODE_SETGID     0x00040000
+#define P9_STAT_MODE_SETVTX     0x00010000
+
+#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
+                                P9_STAT_MODE_SYMLINK |      \
+                                P9_STAT_MODE_LINK |         \
+                                P9_STAT_MODE_DEVICE |       \
+                                P9_STAT_MODE_NAMED_PIPE |   \
+                                P9_STAT_MODE_SOCKET)
+
+/* This is the algorithm from ufs in spfs */
+static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
+{
+    size_t size;
+
+    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
+    memcpy(&qidp->path, &stbuf->st_ino, size);
+    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
+    qidp->type = 0;
+    if (S_ISDIR(stbuf->st_mode)) {
+        qidp->type |= P9_QID_TYPE_DIR;
+    }
+    if (S_ISLNK(stbuf->st_mode)) {
+        qidp->type |= P9_QID_TYPE_SYMLINK;
+    }
+}
+
+static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
+{
+    struct stat stbuf;
+    int err;
+
+    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
+    if (err) {
+        return err;
+    }
+
+    stat_to_qid(&stbuf, qidp);
+    return 0;
+}
+
+static V9fsPDU *alloc_pdu(V9fsState *s)
+{
+    V9fsPDU *pdu = NULL;
+
+    if (!QLIST_EMPTY(&s->free_list)) {
+       pdu = QLIST_FIRST(&s->free_list);
+       QLIST_REMOVE(pdu, next);
+    }
+    return pdu;
+}
+
+static void free_pdu(V9fsState *s, V9fsPDU *pdu)
+{
+    if (pdu) {
+        if (debug_9p_pdu) {
+            pprint_pdu(pdu);
+        }
+        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
+    }
+}
+
+size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
+                        size_t offset, size_t size, int pack)
+{
+    int i = 0;
+    size_t copied = 0;
+
+    for (i = 0; size && i < sg_count; i++) {
+        size_t len;
+        if (offset >= sg[i].iov_len) {
+            /* skip this sg */
+            offset -= sg[i].iov_len;
+            continue;
+        } else {
+            len = MIN(sg[i].iov_len - offset, size);
+            if (pack) {
+                memcpy(sg[i].iov_base + offset, addr, len);
+            } else {
+                memcpy(addr, sg[i].iov_base + offset, len);
+            }
+            size -= len;
+            copied += len;
+            addr += len;
+            if (size) {
+                offset = 0;
+                continue;
+            }
+        }
+    }
+
+    return copied;
+}
+
+static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
+{
+    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
+                         offset, size, 0);
+}
+
+static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
+                        size_t size)
+{
+    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
+                             offset, size, 1);
+}
+
+static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
+{
+    size_t pos = 0;
+    int i, j;
+    struct iovec *src_sg;
+    unsigned int num;
+
+    if (rx) {
+        src_sg = pdu->elem.in_sg;
+        num = pdu->elem.in_num;
+    } else {
+        src_sg = pdu->elem.out_sg;
+        num = pdu->elem.out_num;
+    }
+
+    j = 0;
+    for (i = 0; i < num; i++) {
+        if (offset <= pos) {
+            sg[j].iov_base = src_sg[i].iov_base;
+            sg[j].iov_len = src_sg[i].iov_len;
+            j++;
+        } else if (offset < (src_sg[i].iov_len + pos)) {
+            sg[j].iov_base = src_sg[i].iov_base;
+            sg[j].iov_len = src_sg[i].iov_len;
+            sg[j].iov_base += (offset - pos);
+            sg[j].iov_len -= (offset - pos);
+            j++;
+        }
+        pos += src_sg[i].iov_len;
+    }
+
+    return j;
+}
+
+static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
+{
+    size_t old_offset = offset;
+    va_list ap;
+    int i;
+
+    va_start(ap, fmt);
+    for (i = 0; fmt[i]; i++) {
+        switch (fmt[i]) {
+        case 'b': {
+            uint8_t *valp = va_arg(ap, uint8_t *);
+            offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
+            break;
+        }
+        case 'w': {
+            uint16_t val, *valp;
+            valp = va_arg(ap, uint16_t *);
+            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
+            *valp = le16_to_cpu(val);
+            break;
+        }
+        case 'd': {
+            uint32_t val, *valp;
+            valp = va_arg(ap, uint32_t *);
+            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
+            *valp = le32_to_cpu(val);
+            break;
+        }
+        case 'q': {
+            uint64_t val, *valp;
+            valp = va_arg(ap, uint64_t *);
+            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
+            *valp = le64_to_cpu(val);
+            break;
+        }
+        case 'v': {
+            struct iovec *iov = va_arg(ap, struct iovec *);
+            int *iovcnt = va_arg(ap, int *);
+            *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
+            break;
+        }
+        case 's': {
+            V9fsString *str = va_arg(ap, V9fsString *);
+            offset += pdu_unmarshal(pdu, offset, "w", &str->size);
+            /* FIXME: sanity check str->size */
+            str->data = qemu_malloc(str->size + 1);
+            offset += pdu_unpack(str->data, pdu, offset, str->size);
+            str->data[str->size] = 0;
+            break;
+        }
+        case 'Q': {
+            V9fsQID *qidp = va_arg(ap, V9fsQID *);
+            offset += pdu_unmarshal(pdu, offset, "bdq",
+                        &qidp->type, &qidp->version, &qidp->path);
+            break;
+        }
+        case 'S': {
+            V9fsStat *statp = va_arg(ap, V9fsStat *);
+            offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
+                        &statp->size, &statp->type, &statp->dev,
+                        &statp->qid, &statp->mode, &statp->atime,
+                        &statp->mtime, &statp->length,
+                        &statp->name, &statp->uid, &statp->gid,
+                        &statp->muid, &statp->extension,
+                        &statp->n_uid, &statp->n_gid,
+                        &statp->n_muid);
+            break;
+        }
+        case 'I': {
+            V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
+            offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
+                        &iattr->valid, &iattr->mode,
+                        &iattr->uid, &iattr->gid, &iattr->size,
+                        &iattr->atime_sec, &iattr->atime_nsec,
+                        &iattr->mtime_sec, &iattr->mtime_nsec);
+            break;
+        }
+        default:
+            break;
+        }
+    }
+
+    va_end(ap);
+
+    return offset - old_offset;
+}
+
+static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
+{
+    size_t old_offset = offset;
+    va_list ap;
+    int i;
+
+    va_start(ap, fmt);
+    for (i = 0; fmt[i]; i++) {
+        switch (fmt[i]) {
+        case 'b': {
+            uint8_t val = va_arg(ap, int);
+            offset += pdu_pack(pdu, offset, &val, sizeof(val));
+            break;
+        }
+        case 'w': {
+            uint16_t val;
+            cpu_to_le16w(&val, va_arg(ap, int));
+            offset += pdu_pack(pdu, offset, &val, sizeof(val));
+            break;
+        }
+        case 'd': {
+            uint32_t val;
+            cpu_to_le32w(&val, va_arg(ap, uint32_t));
+            offset += pdu_pack(pdu, offset, &val, sizeof(val));
+            break;
+        }
+        case 'q': {
+            uint64_t val;
+            cpu_to_le64w(&val, va_arg(ap, uint64_t));
+            offset += pdu_pack(pdu, offset, &val, sizeof(val));
+            break;
+        }
+        case 'v': {
+            struct iovec *iov = va_arg(ap, struct iovec *);
+            int *iovcnt = va_arg(ap, int *);
+            *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
+            break;
+        }
+        case 's': {
+            V9fsString *str = va_arg(ap, V9fsString *);
+            offset += pdu_marshal(pdu, offset, "w", str->size);
+            offset += pdu_pack(pdu, offset, str->data, str->size);
+            break;
+        }
+        case 'Q': {
+            V9fsQID *qidp = va_arg(ap, V9fsQID *);
+            offset += pdu_marshal(pdu, offset, "bdq",
+                        qidp->type, qidp->version, qidp->path);
+            break;
+        }
+        case 'S': {
+            V9fsStat *statp = va_arg(ap, V9fsStat *);
+            offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
+                        statp->size, statp->type, statp->dev,
+                        &statp->qid, statp->mode, statp->atime,
+                        statp->mtime, statp->length, &statp->name,
+                        &statp->uid, &statp->gid, &statp->muid,
+                        &statp->extension, statp->n_uid,
+                        statp->n_gid, statp->n_muid);
+            break;
+        }
+        case 'A': {
+            V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
+            offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
+                        statp->st_result_mask,
+                        &statp->qid, statp->st_mode,
+                        statp->st_uid, statp->st_gid,
+                        statp->st_nlink, statp->st_rdev,
+                        statp->st_size, statp->st_blksize, statp->st_blocks,
+                        statp->st_atime_sec, statp->st_atime_nsec,
+                        statp->st_mtime_sec, statp->st_mtime_nsec,
+                        statp->st_ctime_sec, statp->st_ctime_nsec,
+                        statp->st_btime_sec, statp->st_btime_nsec,
+                        statp->st_gen, statp->st_data_version);
+            break;
+        }
+        default:
+            break;
+        }
+    }
+    va_end(ap);
+
+    return offset - old_offset;
+}
+
+static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
+{
+    int8_t id = pdu->id + 1; /* Response */
+
+    if (len < 0) {
+        int err = -len;
+        len = 7;
+
+        if (s->proto_version != V9FS_PROTO_2000L) {
+            V9fsString str;
+
+            str.data = strerror(err);
+            str.size = strlen(str.data);
+
+            len += pdu_marshal(pdu, len, "s", &str);
+            id = P9_RERROR;
+        }
+
+        len += pdu_marshal(pdu, len, "d", err);
+
+        if (s->proto_version == V9FS_PROTO_2000L) {
+            id = P9_RLERROR;
+        }
+    }
+
+    /* fill out the header */
+    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
+
+    /* keep these in sync */
+    pdu->size = len;
+    pdu->id = id;
+
+    /* push onto queue and notify */
+    virtqueue_push(s->vq, &pdu->elem, len);
+
+    /* FIXME: we should batch these completions */
+    virtio_notify(&s->vdev, s->vq);
+
+    free_pdu(s, pdu);
+}
+
+static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
+{
+    mode_t ret;
+
+    ret = mode & 0777;
+    if (mode & P9_STAT_MODE_DIR) {
+        ret |= S_IFDIR;
+    }
+
+    if (mode & P9_STAT_MODE_SYMLINK) {
+        ret |= S_IFLNK;
+    }
+    if (mode & P9_STAT_MODE_SOCKET) {
+        ret |= S_IFSOCK;
+    }
+    if (mode & P9_STAT_MODE_NAMED_PIPE) {
+        ret |= S_IFIFO;
+    }
+    if (mode & P9_STAT_MODE_DEVICE) {
+        if (extension && extension->data[0] == 'c') {
+            ret |= S_IFCHR;
+        } else {
+            ret |= S_IFBLK;
+        }
+    }
+
+    if (!(ret&~0777)) {
+        ret |= S_IFREG;
+    }
+
+    if (mode & P9_STAT_MODE_SETUID) {
+        ret |= S_ISUID;
+    }
+    if (mode & P9_STAT_MODE_SETGID) {
+        ret |= S_ISGID;
+    }
+    if (mode & P9_STAT_MODE_SETVTX) {
+        ret |= S_ISVTX;
+    }
+
+    return ret;
+}
+
+static int donttouch_stat(V9fsStat *stat)
+{
+    if (stat->type == -1 &&
+        stat->dev == -1 &&
+        stat->qid.type == -1 &&
+        stat->qid.version == -1 &&
+        stat->qid.path == -1 &&
+        stat->mode == -1 &&
+        stat->atime == -1 &&
+        stat->mtime == -1 &&
+        stat->length == -1 &&
+        !stat->name.size &&
+        !stat->uid.size &&
+        !stat->gid.size &&
+        !stat->muid.size &&
+        stat->n_uid == -1 &&
+        stat->n_gid == -1 &&
+        stat->n_muid == -1) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void v9fs_stat_free(V9fsStat *stat)
+{
+    v9fs_string_free(&stat->name);
+    v9fs_string_free(&stat->uid);
+    v9fs_string_free(&stat->gid);
+    v9fs_string_free(&stat->muid);
+    v9fs_string_free(&stat->extension);
+}
+
+static uint32_t stat_to_v9mode(const struct stat *stbuf)
+{
+    uint32_t mode;
+
+    mode = stbuf->st_mode & 0777;
+    if (S_ISDIR(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_DIR;
+    }
+
+    if (S_ISLNK(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_SYMLINK;
+    }
+
+    if (S_ISSOCK(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_SOCKET;
+    }
+
+    if (S_ISFIFO(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_NAMED_PIPE;
+    }
+
+    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_DEVICE;
+    }
+
+    if (stbuf->st_mode & S_ISUID) {
+        mode |= P9_STAT_MODE_SETUID;
+    }
+
+    if (stbuf->st_mode & S_ISGID) {
+        mode |= P9_STAT_MODE_SETGID;
+    }
+
+    if (stbuf->st_mode & S_ISVTX) {
+        mode |= P9_STAT_MODE_SETVTX;
+    }
+
+    return mode;
+}
+
+static int stat_to_v9stat(V9fsState *s, V9fsString *name,
+                            const struct stat *stbuf,
+                            V9fsStat *v9stat)
+{
+    int err;
+    const char *str;
+
+    memset(v9stat, 0, sizeof(*v9stat));
+
+    stat_to_qid(stbuf, &v9stat->qid);
+    v9stat->mode = stat_to_v9mode(stbuf);
+    v9stat->atime = stbuf->st_atime;
+    v9stat->mtime = stbuf->st_mtime;
+    v9stat->length = stbuf->st_size;
+
+    v9fs_string_null(&v9stat->uid);
+    v9fs_string_null(&v9stat->gid);
+    v9fs_string_null(&v9stat->muid);
+
+    v9stat->n_uid = stbuf->st_uid;
+    v9stat->n_gid = stbuf->st_gid;
+    v9stat->n_muid = 0;
+
+    v9fs_string_null(&v9stat->extension);
+
+    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
+        err = v9fs_do_readlink(s, name, &v9stat->extension);
+        if (err == -1) {
+            err = -errno;
+            return err;
+        }
+        v9stat->extension.data[err] = 0;
+        v9stat->extension.size = err;
+    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
+        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
+                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
+                major(stbuf->st_rdev), minor(stbuf->st_rdev));
+    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
+        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
+                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
+    }
+
+    str = strrchr(name->data, '/');
+    if (str) {
+        str += 1;
+    } else {
+        str = name->data;
+    }
+
+    v9fs_string_sprintf(&v9stat->name, "%s", str);
+
+    v9stat->size = 61 +
+        v9fs_string_size(&v9stat->name) +
+        v9fs_string_size(&v9stat->uid) +
+        v9fs_string_size(&v9stat->gid) +
+        v9fs_string_size(&v9stat->muid) +
+        v9fs_string_size(&v9stat->extension);
+    return 0;
+}
+
+#define P9_STATS_MODE          0x00000001ULL
+#define P9_STATS_NLINK         0x00000002ULL
+#define P9_STATS_UID           0x00000004ULL
+#define P9_STATS_GID           0x00000008ULL
+#define P9_STATS_RDEV          0x00000010ULL
+#define P9_STATS_ATIME         0x00000020ULL
+#define P9_STATS_MTIME         0x00000040ULL
+#define P9_STATS_CTIME         0x00000080ULL
+#define P9_STATS_INO           0x00000100ULL
+#define P9_STATS_SIZE          0x00000200ULL
+#define P9_STATS_BLOCKS        0x00000400ULL
+
+#define P9_STATS_BTIME         0x00000800ULL
+#define P9_STATS_GEN           0x00001000ULL
+#define P9_STATS_DATA_VERSION  0x00002000ULL
+
+#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
+#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
+
+
+static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
+                            V9fsStatDotl *v9lstat)
+{
+    memset(v9lstat, 0, sizeof(*v9lstat));
+
+    v9lstat->st_mode = stbuf->st_mode;
+    v9lstat->st_nlink = stbuf->st_nlink;
+    v9lstat->st_uid = stbuf->st_uid;
+    v9lstat->st_gid = stbuf->st_gid;
+    v9lstat->st_rdev = stbuf->st_rdev;
+    v9lstat->st_size = stbuf->st_size;
+    v9lstat->st_blksize = stbuf->st_blksize;
+    v9lstat->st_blocks = stbuf->st_blocks;
+    v9lstat->st_atime_sec = stbuf->st_atime;
+    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
+    v9lstat->st_mtime_sec = stbuf->st_mtime;
+    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
+    v9lstat->st_ctime_sec = stbuf->st_ctime;
+    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
+    /* Currently we only support BASIC fields in stat */
+    v9lstat->st_result_mask = P9_STATS_BASIC;
+
+    stat_to_qid(stbuf, &v9lstat->qid);
+}
+
+static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
+{
+    while (len && *iovcnt) {
+        if (len < sg->iov_len) {
+            sg->iov_len -= len;
+            sg->iov_base += len;
+            len = 0;
+        } else {
+            len -= sg->iov_len;
+            sg++;
+            *iovcnt -= 1;
+        }
+    }
+
+    return sg;
+}
+
+static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
+{
+    int i;
+    int total = 0;
+
+    for (i = 0; i < *cnt; i++) {
+        if ((total + sg[i].iov_len) > cap) {
+            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
+            i++;
+            break;
+        }
+        total += sg[i].iov_len;
+    }
+
+    *cnt = i;
+
+    return sg;
+}
+
+static void print_sg(struct iovec *sg, int cnt)
+{
+    int i;
+
+    printf("sg[%d]: {", cnt);
+    for (i = 0; i < cnt; i++) {
+        if (i) {
+            printf(", ");
+        }
+        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
+    }
+    printf("}\n");
+}
+
+static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
+{
+    V9fsString str;
+    v9fs_string_init(&str);
+    v9fs_string_copy(&str, dst);
+    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
+    v9fs_string_free(&str);
+}
+
+static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
+{
+    V9fsString version;
+    size_t offset = 7;
+
+    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
+
+    if (!strcmp(version.data, "9P2000.u")) {
+        s->proto_version = V9FS_PROTO_2000U;
+    } else if (!strcmp(version.data, "9P2000.L")) {
+        s->proto_version = V9FS_PROTO_2000L;
+    } else {
+        v9fs_string_sprintf(&version, "unknown");
+    }
+
+    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
+    complete_pdu(s, pdu, offset);
+
+    v9fs_string_free(&version);
+}
+
+static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, afid, n_uname;
+    V9fsString uname, aname;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    size_t offset = 7;
+    ssize_t err;
+
+    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
+
+    fidp = alloc_fid(s, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    fidp->uid = n_uname;
+
+    v9fs_string_sprintf(&fidp->path, "%s", "/");
+    err = fid_to_qid(s, fidp, &qid);
+    if (err) {
+        err = -EINVAL;
+        free_fid(s, fid);
+        goto out;
+    }
+
+    offset += pdu_marshal(pdu, offset, "Q", &qid);
+
+    err = offset;
+out:
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&uname);
+    v9fs_string_free(&aname);
+}
+
+static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
+    if (err) {
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_stat_free(&vs->v9stat);
+    qemu_free(vs);
+}
+
+static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsStatState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+    v9fs_stat_post_lstat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_stat_free(&vs->v9stat);
+    qemu_free(vs);
+}
+
+static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
+                                                                int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsStatStateDotl *vs;
+    ssize_t err = 0;
+    V9fsFidState *fidp;
+    uint64_t request_mask;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    /* Currently we only support BASIC fields in stat, so there is no
+     * need to look at request_mask.
+     */
+    err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
+    v9fs_getattr_post_lstat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+/* From Linux kernel code */
+#define ATTR_MODE    (1 << 0)
+#define ATTR_UID     (1 << 1)
+#define ATTR_GID     (1 << 2)
+#define ATTR_SIZE    (1 << 3)
+#define ATTR_ATIME   (1 << 4)
+#define ATTR_MTIME   (1 << 5)
+#define ATTR_CTIME   (1 << 6)
+#define ATTR_MASK    127
+#define ATTR_ATIME_SET  (1 << 7)
+#define ATTR_MTIME_SET  (1 << 8)
+
+static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
+                                                                  int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & (ATTR_SIZE)) {
+        err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
+    }
+    v9fs_setattr_post_truncate(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
+                                                                   int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    /* If the only valid entry in iattr is ctime we can call
+     * chown(-1,-1) to update the ctime of the file
+     */
+    if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
+            ((vs->v9iattr.valid & ATTR_CTIME)
+            && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
+        if (!(vs->v9iattr.valid & ATTR_UID)) {
+            vs->v9iattr.uid = -1;
+        }
+        if (!(vs->v9iattr.valid & ATTR_GID)) {
+            vs->v9iattr.gid = -1;
+        }
+        err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
+                                                vs->v9iattr.gid);
+    }
+    v9fs_setattr_post_chown(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
+        struct timespec times[2];
+        if (vs->v9iattr.valid & ATTR_ATIME) {
+            if (vs->v9iattr.valid & ATTR_ATIME_SET) {
+                times[0].tv_sec = vs->v9iattr.atime_sec;
+                times[0].tv_nsec = vs->v9iattr.atime_nsec;
+            } else {
+                times[0].tv_nsec = UTIME_NOW;
+            }
+        } else {
+            times[0].tv_nsec = UTIME_OMIT;
+        }
+
+        if (vs->v9iattr.valid & ATTR_MTIME) {
+            if (vs->v9iattr.valid & ATTR_MTIME_SET) {
+                times[1].tv_sec = vs->v9iattr.mtime_sec;
+                times[1].tv_nsec = vs->v9iattr.mtime_nsec;
+            } else {
+                times[1].tv_nsec = UTIME_NOW;
+            }
+        } else {
+            times[1].tv_nsec = UTIME_OMIT;
+        }
+        err = v9fs_do_utimensat(s, &vs->fidp->path, times);
+    }
+    v9fs_setattr_post_utimensat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsSetattrState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & ATTR_MODE) {
+        err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
+    }
+
+    v9fs_setattr_post_chmod(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
+{
+    complete_pdu(s, vs->pdu, err);
+
+    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
+        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
+            v9fs_string_free(&vs->wnames[vs->name_idx]);
+        }
+
+        qemu_free(vs->wnames);
+        qemu_free(vs->qids);
+    }
+}
+
+static void v9fs_walk_marshal(V9fsWalkState *vs)
+{
+    int i;
+    vs->offset = 7;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
+
+    for (i = 0; i < vs->nwnames; i++) {
+        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
+    }
+}
+
+static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
+                                                                int err)
+{
+    if (err == -1) {
+        free_fid(s, vs->newfidp->fid);
+        v9fs_string_free(&vs->path);
+        err = -ENOENT;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
+
+    vs->name_idx++;
+    if (vs->name_idx < vs->nwnames) {
+        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
+                                            vs->wnames[vs->name_idx].data);
+        v9fs_string_copy(&vs->newfidp->path, &vs->path);
+
+        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
+        v9fs_walk_post_newfid_lstat(s, vs, err);
+        return;
+    }
+
+    v9fs_string_free(&vs->path);
+    v9fs_walk_marshal(vs);
+    err = vs->offset;
+out:
+    v9fs_walk_complete(s, vs, err);
+}
+
+static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
+        int err)
+{
+    if (err == -1) {
+        v9fs_string_free(&vs->path);
+        err = -ENOENT;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
+    vs->name_idx++;
+    if (vs->name_idx < vs->nwnames) {
+
+        v9fs_string_sprintf(&vs->path, "%s/%s",
+                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
+        v9fs_string_copy(&vs->fidp->path, &vs->path);
+
+        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+        v9fs_walk_post_oldfid_lstat(s, vs, err);
+        return;
+    }
+
+    v9fs_string_free(&vs->path);
+    v9fs_walk_marshal(vs);
+    err = vs->offset;
+out:
+    v9fs_walk_complete(s, vs, err);
+}
+
+static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, newfid;
+    V9fsWalkState *vs;
+    int err = 0;
+    int i;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->wnames = NULL;
+    vs->qids = NULL;
+    vs->offset = 7;
+
+    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
+                                            &newfid, &vs->nwnames);
+
+    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
+        vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
+
+        vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
+
+        for (i = 0; i < vs->nwnames; i++) {
+            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
+                                            &vs->wnames[i]);
+        }
+    } else if (vs->nwnames > P9_MAXWELEM) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    /* FIXME: is this really valid? */
+    if (fid == newfid) {
+
+        BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
+        v9fs_string_init(&vs->path);
+        vs->name_idx = 0;
+
+        if (vs->name_idx < vs->nwnames) {
+            v9fs_string_sprintf(&vs->path, "%s/%s",
+                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
+            v9fs_string_copy(&vs->fidp->path, &vs->path);
+
+            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+            v9fs_walk_post_oldfid_lstat(s, vs, err);
+            return;
+        }
+    } else {
+        vs->newfidp = alloc_fid(s, newfid);
+        if (vs->newfidp == NULL) {
+            err = -EINVAL;
+            goto out;
+        }
+
+        vs->newfidp->uid = vs->fidp->uid;
+        v9fs_string_init(&vs->path);
+        vs->name_idx = 0;
+        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
+
+        if (vs->name_idx < vs->nwnames) {
+            v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
+                                vs->wnames[vs->name_idx].data);
+            v9fs_string_copy(&vs->newfidp->path, &vs->path);
+
+            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
+            v9fs_walk_post_newfid_lstat(s, vs, err);
+            return;
+        }
+    }
+
+    v9fs_walk_marshal(vs);
+    err = vs->offset;
+out:
+    v9fs_walk_complete(s, vs, err);
+}
+
+static int32_t get_iounit(V9fsState *s, V9fsString *name)
+{
+    struct statfs stbuf;
+    int32_t iounit = 0;
+
+    /*
+     * iounit should be multiples of f_bsize (host filesystem block size
+     * and as well as less than (client msize - P9_IOHDRSZ))
+     */
+    if (!v9fs_do_statfs(s, name, &stbuf)) {
+        iounit = stbuf.f_bsize;
+        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
+    }
+
+    if (!iounit) {
+        iounit = s->msize - P9_IOHDRSZ;
+    }
+    return iounit;
+}
+
+static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
+{
+    if (vs->fidp->fs.dir == NULL) {
+        err = -errno;
+        goto out;
+    }
+    vs->fidp->fid_type = P9_FID_DIR;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+
+}
+
+static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
+{
+    int err;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
+    err = vs->offset;
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
+{
+    if (vs->fidp->fs.fd == -1) {
+        err = -errno;
+        goto out;
+    }
+    vs->fidp->fid_type = P9_FID_FILE;
+    vs->iounit = get_iounit(s, &vs->fidp->path);
+    v9fs_open_post_getiounit(s, vs);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
+{
+    int flags;
+
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qid);
+
+    if (S_ISDIR(vs->stbuf.st_mode)) {
+        vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
+        v9fs_open_post_opendir(s, vs, err);
+    } else {
+        if (s->proto_version == V9FS_PROTO_2000L) {
+            flags = vs->mode;
+            flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
+            /* Ignore direct disk access hint until the server supports it. */
+            flags &= ~O_DIRECT;
+        } else {
+            flags = omode_to_uflags(vs->mode);
+        }
+        vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
+        v9fs_open_post_open(s, vs, err);
+    }
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsOpenState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->mode = 0;
+
+    if (s->proto_version == V9FS_PROTO_2000L) {
+        pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
+    } else {
+        pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
+    }
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
+
+    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+
+    v9fs_open_post_lstat(s, vs, err);
+    return;
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
+{
+    if (err == 0) {
+        v9fs_string_copy(&vs->fidp->path, &vs->fullname);
+        stat_to_qid(&vs->stbuf, &vs->qid);
+        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
+                vs->iounit);
+        err = vs->offset;
+    } else {
+        vs->fidp->fid_type = P9_FID_NONE;
+        err = -errno;
+        if (vs->fidp->fs.fd > 0) {
+            close(vs->fidp->fs.fd);
+        }
+    }
+
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->fullname);
+    qemu_free(vs);
+}
+
+static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
+        int err)
+{
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+
+out:
+    v9fs_post_lcreate(s, vs, err);
+}
+
+static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
+        int err)
+{
+    if (vs->fidp->fs.fd == -1) {
+        err = -errno;
+        goto out;
+    }
+    vs->fidp->fid_type = P9_FID_FILE;
+    vs->iounit =  get_iounit(s, &vs->fullname);
+    v9fs_lcreate_post_get_iounit(s, vs, err);
+    return;
+
+out:
+    v9fs_post_lcreate(s, vs, err);
+}
+
+static void v9fs_lcreate(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid, flags, mode;
+    gid_t gid;
+    V9fsLcreateState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
+            &mode, &gid);
+
+    vs->fidp = lookup_fid(s, dfid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
+             vs->name.data);
+
+    /* Ignore direct disk access hint until the server supports it. */
+    flags &= ~O_DIRECT;
+
+    vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
+            gid, flags, mode);
+    v9fs_lcreate_post_do_open2(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
+{
+    if (err == -1) {
+        err = -errno;
+    }
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    int datasync;
+    int err;
+
+    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        v9fs_post_do_fsync(s, pdu, err);
+        return;
+    }
+    err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
+    v9fs_post_do_fsync(s, pdu, err);
+}
+
+static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    size_t offset = 7;
+    int err;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+
+    err = free_fid(s, fid);
+    if (err < 0) {
+        goto out;
+    }
+
+    offset = 7;
+    err = offset;
+out:
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
+
+static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
+{
+    if (err) {
+        goto out;
+    }
+    v9fs_stat_free(&vs->v9stat);
+    v9fs_string_free(&vs->name);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
+                                    ssize_t err)
+{
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
+    if (err) {
+        goto out;
+    }
+
+    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
+                            &vs->v9stat);
+    if ((vs->len != (vs->v9stat.size + 2)) ||
+            ((vs->count + vs->len) > vs->max_count)) {
+        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
+        v9fs_read_post_seekdir(s, vs, err);
+        return;
+    }
+    vs->count += vs->len;
+    v9fs_stat_free(&vs->v9stat);
+    v9fs_string_free(&vs->name);
+    vs->dir_pos = vs->dent->d_off;
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+    v9fs_read_post_readdir(s, vs, err);
+    return;
+out:
+    v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
+    v9fs_read_post_seekdir(s, vs, err);
+    return;
+
+}
+
+static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
+{
+    if (vs->dent) {
+        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
+        v9fs_string_init(&vs->name);
+        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
+                            vs->dent->d_name);
+        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
+        v9fs_read_post_dir_lstat(s, vs, err);
+        return;
+    }
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    err = vs->offset;
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
+{
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+    v9fs_read_post_readdir(s, vs, err);
+    return;
+}
+
+static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
+                                       ssize_t err)
+{
+    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
+    v9fs_read_post_telldir(s, vs, err);
+    return;
+}
+
+static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
+{
+    if (err  < 0) {
+        /* IO error return the error */
+        err = -errno;
+        goto out;
+    }
+    vs->total += vs->len;
+    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
+    if (vs->total < vs->count && vs->len > 0) {
+        do {
+            if (0) {
+                print_sg(vs->sg, vs->cnt);
+            }
+            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                      vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
+        } while (vs->len == -1 && errno == EINTR);
+        if (vs->len == -1) {
+            err  = -errno;
+        }
+        v9fs_read_post_preadv(s, vs, err);
+        return;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
+    vs->offset += vs->count;
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
+{
+    ssize_t err = 0;
+    int read_count;
+    int64_t xattr_len;
+
+    xattr_len = vs->fidp->fs.xattr.len;
+    read_count = xattr_len - vs->off;
+    if (read_count > vs->count) {
+        read_count = vs->count;
+    } else if (read_count < 0) {
+        /*
+         * read beyond XATTR value
+         */
+        read_count = 0;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
+    vs->offset += pdu_pack(vs->pdu, vs->offset,
+                           ((char *)vs->fidp->fs.xattr.value) + vs->off,
+                           read_count);
+    err = vs->offset;
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->total = 0;
+    vs->len = 0;
+    vs->count = 0;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->fidp->fid_type == P9_FID_DIR) {
+        vs->max_count = vs->count;
+        vs->count = 0;
+        if (vs->off == 0) {
+            v9fs_do_rewinddir(s, vs->fidp->fs.dir);
+        }
+        v9fs_read_post_rewinddir(s, vs, err);
+        return;
+    } else if (vs->fidp->fid_type == P9_FID_FILE) {
+        vs->sg = vs->iov;
+        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
+        vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
+        if (vs->total <= vs->count) {
+            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                                    vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
+            err = vs->len;
+            v9fs_read_post_preadv(s, vs, err);
+        }
+        return;
+    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+        v9fs_xattr_read(s, vs);
+        return;
+    } else {
+        err = -EINVAL;
+    }
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+}
+
+typedef struct V9fsReadDirState {
+    V9fsPDU *pdu;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    off_t saved_dir_pos;
+    struct dirent *dent;
+    int32_t count;
+    int32_t max_count;
+    size_t offset;
+    int64_t initial_offset;
+    V9fsString name;
+} V9fsReadDirState;
+
+static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+    return;
+}
+
+/* Size of each dirent on the wire: size of qid (13) + size of offset (8)
+ * size of type (1) + size of name.size (2) + strlen(name.data)
+ */
+#define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
+
+static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    int len;
+    size_t size;
+
+    if (vs->dent) {
+        v9fs_string_init(&vs->name);
+        v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
+
+        if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
+            /* Ran out of buffer. Set dir back to old position and return */
+            v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->saved_dir_pos);
+            v9fs_readdir_post_seekdir(s, vs);
+            return;
+        }
+
+        /* Fill up just the path field of qid because the client uses
+         * only that. To fill the entire qid structure we will have
+         * to stat each dirent found, which is expensive
+         */
+        size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
+        memcpy(&vs->qid.path, &vs->dent->d_ino, size);
+        /* Fill the other fields with dummy values */
+        vs->qid.type = 0;
+        vs->qid.version = 0;
+
+        len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
+                              &vs->qid, vs->dent->d_off,
+                              vs->dent->d_type, &vs->name);
+        vs->count += len;
+        v9fs_string_free(&vs->name);
+        vs->saved_dir_pos = vs->dent->d_off;
+        vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+        v9fs_readdir_post_readdir(s, vs);
+        return;
+    }
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+    v9fs_readdir_post_readdir(s, vs);
+    return;
+}
+
+static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
+    v9fs_readdir_post_telldir(s, vs);
+    return;
+}
+
+static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadDirState *vs;
+    ssize_t err = 0;
+    size_t offset = 7;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->count = 0;
+
+    pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
+                                                        &vs->max_count);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL || !(vs->fidp->fs.dir)) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->initial_offset == 0) {
+        v9fs_do_rewinddir(s, vs->fidp->fs.dir);
+    } else {
+        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->initial_offset);
+    }
+
+    v9fs_readdir_post_setdir(s, vs);
+    return;
+
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
+                                   ssize_t err)
+{
+    if (err  < 0) {
+        /* IO error return the error */
+        err = -errno;
+        goto out;
+    }
+    vs->total += vs->len;
+    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
+    if (vs->total < vs->count && vs->len > 0) {
+        do {
+            if (0) {
+                print_sg(vs->sg, vs->cnt);
+            }
+            vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                      vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
+        } while (vs->len == -1 && errno == EINTR);
+        if (vs->len == -1) {
+            err  = -errno;
+        }
+        v9fs_write_post_pwritev(s, vs, err);
+        return;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
+{
+    int i, to_copy;
+    ssize_t err = 0;
+    int write_count;
+    int64_t xattr_len;
+
+    xattr_len = vs->fidp->fs.xattr.len;
+    write_count = xattr_len - vs->off;
+    if (write_count > vs->count) {
+        write_count = vs->count;
+    } else if (write_count < 0) {
+        /*
+         * write beyond XATTR value len specified in
+         * xattrcreate
+         */
+        err = -ENOSPC;
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
+    err = vs->offset;
+    vs->fidp->fs.xattr.copied_len += write_count;
+    /*
+     * Now copy the content from sg list
+     */
+    for (i = 0; i < vs->cnt; i++) {
+        if (write_count > vs->sg[i].iov_len) {
+            to_copy = vs->sg[i].iov_len;
+        } else {
+            to_copy = write_count;
+        }
+        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
+               vs->sg[i].iov_base, to_copy);
+        /* updating vs->off since we are not using below */
+        vs->off += to_copy;
+        write_count -= to_copy;
+    }
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsWriteState *vs;
+    ssize_t err;
+
+    vs = qemu_malloc(sizeof(*vs));
+
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->sg = vs->iov;
+    vs->total = 0;
+    vs->len = 0;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
+                  vs->sg, &vs->cnt);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->fidp->fid_type == P9_FID_FILE) {
+        if (vs->fidp->fs.fd == -1) {
+            err = -EINVAL;
+            goto out;
+        }
+    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+        /*
+         * setxattr operation
+         */
+        v9fs_xattr_write(s, vs);
+        return;
+    } else {
+        err = -EINVAL;
+        goto out;
+    }
+    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
+    if (vs->total <= vs->count) {
+        vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
+        if (vs->len > 0) {
+            vs->off += vs->len;
+        }
+        err = vs->len;
+        v9fs_write_post_pwritev(s, vs, err);
+    }
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
+{
+    int err;
+    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
+    stat_to_qid(&vs->stbuf, &vs->qid);
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
+    err = vs->offset;
+
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->extension);
+    v9fs_string_free(&vs->fullname);
+    qemu_free(vs);
+}
+
+static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (err == 0) {
+        vs->iounit = get_iounit(s, &vs->fidp->path);
+        v9fs_create_post_getiounit(s, vs);
+        return;
+    }
+
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->extension);
+    v9fs_string_free(&vs->fullname);
+    qemu_free(vs);
+}
+
+static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (err) {
+        err = -errno;
+    }
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
+                                                                    int err)
+{
+    if (!vs->fidp->fs.dir) {
+        err = -errno;
+    }
+    vs->fidp->fid_type = P9_FID_DIR;
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
+                                                                    int err)
+{
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
+    v9fs_create_post_opendir(s, vs, err);
+    return;
+
+out:
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_create_post_dir_lstat(s, vs, err);
+    return;
+
+out:
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (err) {
+        vs->fidp->fid_type = P9_FID_NONE;
+        close(vs->fidp->fs.fd);
+        err = -errno;
+    }
+    v9fs_post_create(s, vs, err);
+    return;
+}
+
+static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
+{
+    if (vs->fidp->fs.fd == -1) {
+        err = -errno;
+        goto out;
+    }
+    vs->fidp->fid_type = P9_FID_FILE;
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    v9fs_create_post_fstat(s, vs, err);
+
+    return;
+
+out:
+    v9fs_post_create(s, vs, err);
+
+}
+
+static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
+{
+
+    if (err == 0 || errno != ENOENT) {
+        err = -errno;
+        goto out;
+    }
+
+    if (vs->perm & P9_STAT_MODE_DIR) {
+        err = v9fs_do_mkdir(s, vs->fullname.data, vs->perm & 0777,
+                vs->fidp->uid, -1);
+        v9fs_create_post_mkdir(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
+        err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
+                vs->fullname.data, -1);
+        v9fs_create_post_perms(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_LINK) {
+        int32_t nfid = atoi(vs->extension.data);
+        V9fsFidState *nfidp = lookup_fid(s, nfid);
+        if (nfidp == NULL) {
+            err = -errno;
+            v9fs_post_create(s, vs, err);
+        }
+        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
+        v9fs_create_post_perms(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
+        char ctype;
+        uint32_t major, minor;
+        mode_t nmode = 0;
+
+        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
+                                        &minor) != 3) {
+            err = -errno;
+            v9fs_post_create(s, vs, err);
+        }
+
+        switch (ctype) {
+        case 'c':
+            nmode = S_IFCHR;
+            break;
+        case 'b':
+            nmode = S_IFBLK;
+            break;
+        default:
+            err = -EIO;
+            v9fs_post_create(s, vs, err);
+        }
+
+        nmode |= vs->perm & 0777;
+        err = v9fs_do_mknod(s, vs->fullname.data, nmode,
+                makedev(major, minor), vs->fidp->uid, -1);
+        v9fs_create_post_perms(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
+        err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
+                0, vs->fidp->uid, -1);
+        v9fs_post_create(s, vs, err);
+    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
+        err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
+                0, vs->fidp->uid, -1);
+        v9fs_post_create(s, vs, err);
+    } else {
+        vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
+                -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
+
+        v9fs_create_post_open2(s, vs, err);
+    }
+
+    return;
+
+out:
+    v9fs_post_create(s, vs, err);
+}
+
+static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsCreateState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
+                                &vs->perm, &vs->mode, &vs->extension);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
+                                                        vs->name.data);
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_create_post_lstat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->extension);
+    qemu_free(vs);
+}
+
+static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
+{
+    if (err == 0) {
+        stat_to_qid(&vs->stbuf, &vs->qid);
+        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+        err = vs->offset;
+    } else {
+        err = -errno;
+    }
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->symname);
+    v9fs_string_free(&vs->fullname);
+    qemu_free(vs);
+}
+
+static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
+        int err)
+{
+    if (err) {
+        goto out;
+    }
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+out:
+    v9fs_post_symlink(s, vs, err);
+}
+
+static void v9fs_symlink(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid;
+    V9fsSymlinkState *vs;
+    int err = 0;
+    gid_t gid;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
+            &vs->symname, &gid);
+
+    vs->dfidp = lookup_fid(s, dfid);
+    if (vs->dfidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
+            vs->name.data);
+    err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
+            vs->fullname.data, gid);
+    v9fs_symlink_post_do_symlink(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->symname);
+    qemu_free(vs);
+}
+
+static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
+{
+    /* A nop call with no return */
+    complete_pdu(s, pdu, 7);
+}
+
+static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid, oldfid;
+    V9fsFidState *dfidp, *oldfidp;
+    V9fsString name, fullname;
+    size_t offset = 7;
+    int err = 0;
+
+    v9fs_string_init(&fullname);
+
+    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
+
+    dfidp = lookup_fid(s, dfid);
+    if (dfidp == NULL) {
+        err = -errno;
+        goto out;
+    }
+
+    oldfidp = lookup_fid(s, oldfid);
+    if (oldfidp == NULL) {
+        err = -errno;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
+    err = offset;
+    err = v9fs_do_link(s, &oldfidp->path, &fullname);
+    if (err) {
+        err = -errno;
+    }
+    v9fs_string_free(&fullname);
+
+out:
+    v9fs_string_free(&name);
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
+                                                                int err)
+{
+    if (err < 0) {
+        err = -errno;
+    } else {
+        err = vs->offset;
+    }
+
+    /* For TREMOVE we need to clunk the fid even on failed remove */
+    free_fid(s, vs->fidp->fid);
+
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsRemoveState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    err = v9fs_do_remove(s, &vs->fidp->path);
+    v9fs_remove_post_remove(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    err = vs->offset;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+    if (vs->v9stat.length != -1) {
+        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
+            err = -errno;
+        }
+    }
+    v9fs_wstat_post_truncate(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
+{
+    int err = 0;
+    char *old_name, *new_name;
+    char *end;
+
+    if (vs->newdirfid != -1) {
+        V9fsFidState *dirfidp;
+        dirfidp = lookup_fid(s, vs->newdirfid);
+
+        if (dirfidp == NULL) {
+            err = -ENOENT;
+            goto out;
+        }
+
+        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
+
+        new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
+
+        strcpy(new_name, dirfidp->path.data);
+        strcat(new_name, "/");
+        strcat(new_name + dirfidp->path.size, vs->name.data);
+    } else {
+        old_name = vs->fidp->path.data;
+        end = strrchr(old_name, '/');
+        if (end) {
+            end++;
+        } else {
+            end = old_name;
+        }
+        new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
+
+        strncat(new_name, old_name, end - old_name);
+        strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
+    }
+
+    v9fs_string_free(&vs->name);
+    vs->name.data = qemu_strdup(new_name);
+    vs->name.size = strlen(new_name);
+
+    if (strcmp(new_name, vs->fidp->path.data) != 0) {
+        if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
+            err = -errno;
+        } else {
+            V9fsFidState *fidp;
+            /*
+            * Fixup fid's pointing to the old name to
+            * start pointing to the new name
+            */
+            for (fidp = s->fid_list; fidp; fidp = fidp->next) {
+                if (vs->fidp == fidp) {
+                    /*
+                    * we replace name of this fid towards the end
+                    * so that our below strcmp will work
+                    */
+                    continue;
+                }
+                if (!strncmp(vs->fidp->path.data, fidp->path.data,
+                    strlen(vs->fidp->path.data))) {
+                    /* replace the name */
+                    v9fs_fix_path(&fidp->path, &vs->name,
+                                  strlen(vs->fidp->path.data));
+                }
+            }
+            v9fs_string_copy(&vs->fidp->path, &vs->name);
+        }
+    }
+out:
+    v9fs_string_free(&vs->name);
+    return err;
+}
+
+static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
+{
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    if (vs->v9stat.name.size != 0) {
+        V9fsRenameState *vr;
+
+        vr = qemu_mallocz(sizeof(V9fsRenameState));
+        vr->newdirfid = -1;
+        vr->pdu = vs->pdu;
+        vr->fidp = vs->fidp;
+        vr->offset = vs->offset;
+        vr->name.size = vs->v9stat.name.size;
+        vr->name.data = qemu_strdup(vs->v9stat.name.data);
+
+        err = v9fs_complete_rename(s, vr);
+        qemu_free(vr);
+    }
+    v9fs_wstat_post_rename(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_rename(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsRenameState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
+
+    err = v9fs_complete_rename(s, vs);
+    v9fs_rename_post_rename(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
+        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
+                    vs->v9stat.n_gid)) {
+            err = -errno;
+        }
+    }
+    v9fs_wstat_post_chown(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
+        struct timespec times[2];
+        if (vs->v9stat.atime != -1) {
+            times[0].tv_sec = vs->v9stat.atime;
+            times[0].tv_nsec = 0;
+        } else {
+            times[0].tv_nsec = UTIME_OMIT;
+        }
+        if (vs->v9stat.mtime != -1) {
+            times[1].tv_sec = vs->v9stat.mtime;
+            times[1].tv_nsec = 0;
+        } else {
+            times[1].tv_nsec = UTIME_OMIT;
+        }
+
+        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
+            err = -errno;
+        }
+    }
+
+    v9fs_wstat_post_utime(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+    }
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    uint32_t v9_mode;
+
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    v9_mode = stat_to_v9mode(&vs->stbuf);
+
+    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
+        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
+            /* Attempting to change the type */
+            err = -EIO;
+            goto out;
+    }
+
+    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
+                    &vs->v9stat.extension))) {
+            err = -errno;
+     }
+    v9fs_wstat_post_chmod(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsWstatState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    /* do we need to sync the file? */
+    if (donttouch_stat(&vs->v9stat)) {
+        err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
+        v9fs_wstat_post_fsync(s, vs, err);
+        return;
+    }
+
+    if (vs->v9stat.mode != -1) {
+        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
+        v9fs_wstat_post_lstat(s, vs, err);
+        return;
+    }
+
+    v9fs_wstat_post_chmod(s, vs, err);
+    return;
+
+out:
+    v9fs_stat_free(&vs->v9stat);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
+{
+    int32_t bsize_factor;
+
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    /*
+     * compute bsize factor based on host file system block size
+     * and client msize
+     */
+    bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
+    if (!bsize_factor) {
+        bsize_factor = 1;
+    }
+    vs->v9statfs.f_type = vs->stbuf.f_type;
+    vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
+    vs->v9statfs.f_bsize *= bsize_factor;
+    /*
+     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
+     * adjust(divide) the number of blocks, free blocks and available
+     * blocks by bsize factor
+     */
+    vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
+    vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
+    vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
+    vs->v9statfs.f_files = vs->stbuf.f_files;
+    vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
+    vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
+                       (unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
+    vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
+         vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
+         vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
+         vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
+         vs->v9statfs.f_namelen);
+
+out:
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+}
+
+static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
+{
+    V9fsStatfsState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
+
+    vs->fidp = lookup_fid(s, vs->fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
+    v9fs_statfs_post_statfs(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qid);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod_post_mknod(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_mknod_post_lstat(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsMkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+    gid_t gid;
+    int mode;
+    int major, minor;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+    pdu_unmarshal(vs->pdu, vs->offset, "dsdddd", &fid, &vs->name, &mode,
+        &major, &minor, &gid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
+    err = v9fs_do_mknod(s, vs->fullname.data, mode, makedev(major, minor),
+        fidp->uid, gid);
+    v9fs_mknod_post_mknod(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+/*
+ * Implement posix byte range locking code
+ * Server side handling of locking code is very simple, because 9p server in
+ * QEMU can handle only one client. And most of the lock handling
+ * (like conflict, merging) etc is done by the VFS layer itself, so no need to
+ * do any thing in * qemu 9p server side lock code path.
+ * So when a TLOCK request comes, always return success
+ */
+
+static void v9fs_lock(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, err = 0;
+    V9fsLockState *vs;
+
+    vs = qemu_mallocz(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    vs->flock = qemu_malloc(sizeof(*vs->flock));
+    pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
+                &vs->flock->flags, &vs->flock->start, &vs->flock->length,
+                            &vs->flock->proc_id, &vs->flock->client_id);
+
+    vs->status = P9_LOCK_ERROR;
+
+    /* We support only block flag now (that too ignored currently) */
+    if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
+        err = -EINVAL;
+        goto out;
+    }
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->status = P9_LOCK_SUCCESS;
+out:
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs->flock);
+    qemu_free(vs);
+}
+
+/*
+ * When a TGETLOCK request comes, always return success because all lock
+ * handling is done by client's VFS layer.
+ */
+
+static void v9fs_getlock(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, err = 0;
+    V9fsGetlockState *vs;
+
+    vs = qemu_mallocz(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    vs->glock = qemu_malloc(sizeof(*vs->glock));
+    pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
+                &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
+               &vs->glock->client_id);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->glock->type = F_UNLCK;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
+                vs->glock->start, vs->glock->length, vs->glock->proc_id,
+               &vs->glock->client_id);
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs->glock);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qid);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir_post_mkdir(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_mkdir_post_lstat(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsMkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+    gid_t gid;
+    int mode;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+    pdu_unmarshal(vs->pdu, vs->offset, "dsdd", &fid, &vs->name, &mode,
+        &gid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
+    err = v9fs_do_mkdir(s, vs->fullname.data, mode, fidp->uid, gid);
+    v9fs_mkdir_post_mkdir(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_post_xattr_getvalue(V9fsState *s, V9fsXattrState *vs, int err)
+{
+
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_post_xattr_check(V9fsState *s, V9fsXattrState *vs, ssize_t err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    /*
+     * Read the xattr value
+     */
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = -1;
+    if (vs->size) {
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+        err = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
+                                &vs->name, vs->xattr_fidp->fs.xattr.value,
+                                vs->xattr_fidp->fs.xattr.len);
+    }
+    v9fs_post_xattr_getvalue(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_post_lxattr_getvalue(V9fsState *s,
+                                      V9fsXattrState *vs, int err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_post_lxattr_check(V9fsState *s,
+                                   V9fsXattrState *vs, ssize_t err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    /*
+     * Read the xattr value
+     */
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = -1;
+    if (vs->size) {
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+        err = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
+                                 vs->xattr_fidp->fs.xattr.value,
+                                 vs->xattr_fidp->fs.xattr.len);
+    }
+    v9fs_post_lxattr_getvalue(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_xattrwalk(V9fsState *s, V9fsPDU *pdu)
+{
+    ssize_t err = 0;
+    V9fsXattrState *vs;
+    int32_t fid, newfid;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &newfid, &vs->name);
+    vs->file_fidp = lookup_fid(s, fid);
+    if (vs->file_fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    vs->xattr_fidp = alloc_fid(s, newfid);
+    if (vs->xattr_fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    v9fs_string_copy(&vs->xattr_fidp->path, &vs->file_fidp->path);
+    if (vs->name.data[0] == 0) {
+        /*
+         * listxattr request. Get the size first
+         */
+        vs->size = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
+                                      NULL, 0);
+        if (vs->size < 0) {
+            err = vs->size;
+        }
+        v9fs_post_lxattr_check(s, vs, err);
+        return;
+    } else {
+        /*
+         * specific xattr fid. We check for xattr
+         * presence also collect the xattr size
+         */
+        vs->size = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
+                                     &vs->name, NULL, 0);
+        if (vs->size < 0) {
+            err = vs->size;
+        }
+        v9fs_post_xattr_check(s, vs, err);
+        return;
+    }
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
+{
+    int flags;
+    int32_t fid;
+    ssize_t err = 0;
+    V9fsXattrState *vs;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
+                  &fid, &vs->name, &vs->size, &flags);
+
+    vs->file_fidp = lookup_fid(s, fid);
+    if (vs->file_fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    /* Make the file fid point to xattr */
+    vs->xattr_fidp = vs->file_fidp;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = 0;
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fs.xattr.flags = flags;
+    v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
+    v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
+    if (vs->size)
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+    else
+        vs->xattr_fidp->fs.xattr.value = NULL;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_readlink_post_readlink(V9fsState *s, V9fsReadLinkState *vs,
+                                                    int err)
+{
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "s", &vs->target);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->target);
+    qemu_free(vs);
+}
+
+static void v9fs_readlink(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadLinkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_init(&vs->target);
+    err = v9fs_do_readlink(s, &fidp->path, &vs->target);
+    v9fs_readlink_post_readlink(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
+
+static pdu_handler_t *pdu_handlers[] = {
+    [P9_TREADDIR] = v9fs_readdir,
+    [P9_TSTATFS] = v9fs_statfs,
+    [P9_TGETATTR] = v9fs_getattr,
+    [P9_TSETATTR] = v9fs_setattr,
+    [P9_TXATTRWALK] = v9fs_xattrwalk,
+    [P9_TXATTRCREATE] = v9fs_xattrcreate,
+    [P9_TMKNOD] = v9fs_mknod,
+    [P9_TRENAME] = v9fs_rename,
+    [P9_TLOCK] = v9fs_lock,
+    [P9_TGETLOCK] = v9fs_getlock,
+    [P9_TREADLINK] = v9fs_readlink,
+    [P9_TMKDIR] = v9fs_mkdir,
+    [P9_TVERSION] = v9fs_version,
+    [P9_TLOPEN] = v9fs_open,
+    [P9_TATTACH] = v9fs_attach,
+    [P9_TSTAT] = v9fs_stat,
+    [P9_TWALK] = v9fs_walk,
+    [P9_TCLUNK] = v9fs_clunk,
+    [P9_TFSYNC] = v9fs_fsync,
+    [P9_TOPEN] = v9fs_open,
+    [P9_TREAD] = v9fs_read,
+#if 0
+    [P9_TAUTH] = v9fs_auth,
+#endif
+    [P9_TFLUSH] = v9fs_flush,
+    [P9_TLINK] = v9fs_link,
+    [P9_TSYMLINK] = v9fs_symlink,
+    [P9_TCREATE] = v9fs_create,
+    [P9_TLCREATE] = v9fs_lcreate,
+    [P9_TWRITE] = v9fs_write,
+    [P9_TWSTAT] = v9fs_wstat,
+    [P9_TREMOVE] = v9fs_remove,
+};
+
+static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
+{
+    pdu_handler_t *handler;
+
+    if (debug_9p_pdu) {
+        pprint_pdu(pdu);
+    }
+
+    BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
+
+    handler = pdu_handlers[pdu->id];
+    BUG_ON(handler == NULL);
+
+    handler(s, pdu);
+}
+
+static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    V9fsState *s = (V9fsState *)vdev;
+    V9fsPDU *pdu;
+    ssize_t len;
+
+    while ((pdu = alloc_pdu(s)) &&
+            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
+        uint8_t *ptr;
+
+        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
+        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
+
+        ptr = pdu->elem.out_sg[0].iov_base;
+
+        memcpy(&pdu->size, ptr, 4);
+        pdu->id = ptr[4];
+        memcpy(&pdu->tag, ptr + 5, 2);
+
+        submit_pdu(s, pdu);
+    }
+
+    free_pdu(s, pdu);
+}
+
+static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
+{
+    features |= 1 << VIRTIO_9P_MOUNT_TAG;
+    return features;
+}
+
+static V9fsState *to_virtio_9p(VirtIODevice *vdev)
+{
+    return (V9fsState *)vdev;
+}
+
+static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    struct virtio_9p_config *cfg;
+    V9fsState *s = to_virtio_9p(vdev);
+
+    cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
+                        s->tag_len);
+    stw_raw(&cfg->tag_len, s->tag_len);
+    memcpy(cfg->tag, s->tag, s->tag_len);
+    memcpy(config, cfg, s->config_size);
+    qemu_free(cfg);
+}
+
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
+ {
+    V9fsState *s;
+    int i, len;
+    struct stat stat;
+    FsTypeEntry *fse;
+
+
+    s = (V9fsState *)virtio_common_init("virtio-9p",
+                                    VIRTIO_ID_9P,
+                                    sizeof(struct virtio_9p_config)+
+                                    MAX_TAG_LEN,
+                                    sizeof(V9fsState));
+
+    /* initialize pdu allocator */
+    QLIST_INIT(&s->free_list);
+    for (i = 0; i < (MAX_REQ - 1); i++) {
+       QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
+    }
+
+    s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
+
+    fse = get_fsdev_fsentry(conf->fsdev_id);
+
+    if (!fse) {
+        /* We don't have a fsdev identified by fsdev_id */
+        fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
+                "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
+        exit(1);
+    }
+
+    if (!fse->path || !conf->tag) {
+        /* we haven't specified a mount_tag or the path */
+        fprintf(stderr, "fsdev with id %s needs path "
+                "and Virtio-9p device needs mount_tag arguments\n",
+                conf->fsdev_id);
+        exit(1);
+    }
+
+    if (!strcmp(fse->security_model, "passthrough")) {
+        /* Files on the Fileserver set to client user credentials */
+        s->ctx.fs_sm = SM_PASSTHROUGH;
+        s->ctx.xops = passthrough_xattr_ops;
+    } else if (!strcmp(fse->security_model, "mapped")) {
+        /* Files on the fileserver are set to QEMU credentials.
+         * Client user credentials are saved in extended attributes.
+         */
+        s->ctx.fs_sm = SM_MAPPED;
+        s->ctx.xops = mapped_xattr_ops;
+    } else if (!strcmp(fse->security_model, "none")) {
+        /*
+         * Files on the fileserver are set to QEMU credentials.
+         */
+        s->ctx.fs_sm = SM_NONE;
+        s->ctx.xops = none_xattr_ops;
+    } else {
+        fprintf(stderr, "Default to security_model=none. You may want"
+                " enable advanced security model using "
+                "security option:\n\t security_model=passthrough \n\t "
+                "security_model=mapped\n");
+        s->ctx.fs_sm = SM_NONE;
+        s->ctx.xops = none_xattr_ops;
+    }
+
+    if (lstat(fse->path, &stat)) {
+        fprintf(stderr, "share path %s does not exist\n", fse->path);
+        exit(1);
+    } else if (!S_ISDIR(stat.st_mode)) {
+        fprintf(stderr, "share path %s is not a directory \n", fse->path);
+        exit(1);
+    }
+
+    s->ctx.fs_root = qemu_strdup(fse->path);
+    len = strlen(conf->tag);
+    if (len > MAX_TAG_LEN) {
+        len = MAX_TAG_LEN;
+    }
+    /* s->tag is non-NULL terminated string */
+    s->tag = qemu_malloc(len);
+    memcpy(s->tag, conf->tag, len);
+    s->tag_len = len;
+    s->ctx.uid = -1;
+
+    s->ops = fse->ops;
+    s->vdev.get_features = virtio_9p_get_features;
+    s->config_size = sizeof(struct virtio_9p_config) +
+                        s->tag_len;
+    s->vdev.get_config = virtio_9p_get_config;
+
+    return &s->vdev;
+}
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
new file mode 100644 (file)
index 0000000..622928f
--- /dev/null
@@ -0,0 +1,507 @@
+#ifndef _QEMU_VIRTIO_9P_H
+#define _QEMU_VIRTIO_9P_H
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <utime.h>
+
+#include "fsdev/file-op-9p.h"
+
+/* The feature bitmap for virtio 9P */
+/* The mount point is specified in a config variable */
+#define VIRTIO_9P_MOUNT_TAG 0
+
+enum {
+    P9_TLERROR = 6,
+    P9_RLERROR,
+    P9_TSTATFS = 8,
+    P9_RSTATFS,
+    P9_TLOPEN = 12,
+    P9_RLOPEN,
+    P9_TLCREATE = 14,
+    P9_RLCREATE,
+    P9_TSYMLINK = 16,
+    P9_RSYMLINK,
+    P9_TMKNOD = 18,
+    P9_RMKNOD,
+    P9_TRENAME = 20,
+    P9_RRENAME,
+    P9_TREADLINK = 22,
+    P9_RREADLINK,
+    P9_TGETATTR = 24,
+    P9_RGETATTR,
+    P9_TSETATTR = 26,
+    P9_RSETATTR,
+    P9_TXATTRWALK = 30,
+    P9_RXATTRWALK,
+    P9_TXATTRCREATE = 32,
+    P9_RXATTRCREATE,
+    P9_TREADDIR = 40,
+    P9_RREADDIR,
+    P9_TFSYNC = 50,
+    P9_RFSYNC,
+    P9_TLOCK = 52,
+    P9_RLOCK,
+    P9_TGETLOCK = 54,
+    P9_RGETLOCK,
+    P9_TLINK = 70,
+    P9_RLINK,
+    P9_TMKDIR = 72,
+    P9_RMKDIR,
+    P9_TVERSION = 100,
+    P9_RVERSION,
+    P9_TAUTH = 102,
+    P9_RAUTH,
+    P9_TATTACH = 104,
+    P9_RATTACH,
+    P9_TERROR = 106,
+    P9_RERROR,
+    P9_TFLUSH = 108,
+    P9_RFLUSH,
+    P9_TWALK = 110,
+    P9_RWALK,
+    P9_TOPEN = 112,
+    P9_ROPEN,
+    P9_TCREATE = 114,
+    P9_RCREATE,
+    P9_TREAD = 116,
+    P9_RREAD,
+    P9_TWRITE = 118,
+    P9_RWRITE,
+    P9_TCLUNK = 120,
+    P9_RCLUNK,
+    P9_TREMOVE = 122,
+    P9_RREMOVE,
+    P9_TSTAT = 124,
+    P9_RSTAT,
+    P9_TWSTAT = 126,
+    P9_RWSTAT,
+};
+
+
+/* qid.types */
+enum {
+    P9_QTDIR = 0x80,
+    P9_QTAPPEND = 0x40,
+    P9_QTEXCL = 0x20,
+    P9_QTMOUNT = 0x10,
+    P9_QTAUTH = 0x08,
+    P9_QTTMP = 0x04,
+    P9_QTSYMLINK = 0x02,
+    P9_QTLINK = 0x01,
+    P9_QTFILE = 0x00,
+};
+
+enum p9_proto_version {
+    V9FS_PROTO_2000U = 0x01,
+    V9FS_PROTO_2000L = 0x02,
+};
+
+#define P9_NOTAG    (u16)(~0)
+#define P9_NOFID    (u32)(~0)
+#define P9_MAXWELEM 16
+
+/*
+ * ample room for Twrite/Rread header
+ * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4]
+ */
+#define P9_IOHDRSZ 24
+
+typedef struct V9fsPDU V9fsPDU;
+
+struct V9fsPDU
+{
+    uint32_t size;
+    uint16_t tag;
+    uint8_t id;
+    VirtQueueElement elem;
+    QLIST_ENTRY(V9fsPDU) next;
+};
+
+
+/* FIXME
+ * 1) change user needs to set groups and stuff
+ */
+
+/* from Linux's linux/virtio_9p.h */
+
+/* The ID for virtio console */
+#define VIRTIO_ID_9P    9
+#define MAX_REQ         128
+#define MAX_TAG_LEN     32
+
+#define BUG_ON(cond) assert(!(cond))
+
+typedef struct V9fsFidState V9fsFidState;
+
+typedef struct V9fsString
+{
+    int16_t size;
+    char *data;
+} V9fsString;
+
+typedef struct V9fsQID
+{
+    int8_t type;
+    int32_t version;
+    int64_t path;
+} V9fsQID;
+
+typedef struct V9fsStat
+{
+    int16_t size;
+    int16_t type;
+    int32_t dev;
+    V9fsQID qid;
+    int32_t mode;
+    int32_t atime;
+    int32_t mtime;
+    int64_t length;
+    V9fsString name;
+    V9fsString uid;
+    V9fsString gid;
+    V9fsString muid;
+    /* 9p2000.u */
+    V9fsString extension;
+   int32_t n_uid;
+    int32_t n_gid;
+    int32_t n_muid;
+} V9fsStat;
+
+enum {
+    P9_FID_NONE = 0,
+    P9_FID_FILE,
+    P9_FID_DIR,
+    P9_FID_XATTR,
+};
+
+typedef struct V9fsXattr
+{
+    int64_t copied_len;
+    int64_t len;
+    void *value;
+    V9fsString name;
+    int flags;
+} V9fsXattr;
+
+struct V9fsFidState
+{
+    int fid_type;
+    int32_t fid;
+    V9fsString path;
+    union {
+       int fd;
+       DIR *dir;
+       V9fsXattr xattr;
+    } fs;
+    uid_t uid;
+    V9fsFidState *next;
+};
+
+typedef struct V9fsState
+{
+    VirtIODevice vdev;
+    VirtQueue *vq;
+    V9fsPDU pdus[MAX_REQ];
+    QLIST_HEAD(, V9fsPDU) free_list;
+    V9fsFidState *fid_list;
+    FileOperations *ops;
+    FsContext ctx;
+    uint16_t tag_len;
+    uint8_t *tag;
+    size_t config_size;
+    enum p9_proto_version proto_version;
+    int32_t msize;
+} V9fsState;
+
+typedef struct V9fsCreateState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    int32_t perm;
+    int8_t mode;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString extension;
+    V9fsString fullname;
+    int iounit;
+} V9fsCreateState;
+
+typedef struct V9fsLcreateState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    int32_t iounit;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString fullname;
+} V9fsLcreateState;
+
+typedef struct V9fsStatState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsStat v9stat;
+    V9fsFidState *fidp;
+    struct stat stbuf;
+} V9fsStatState;
+
+typedef struct V9fsStatDotl {
+    uint64_t st_result_mask;
+    V9fsQID qid;
+    uint32_t st_mode;
+    uint32_t st_uid;
+    uint32_t st_gid;
+    uint64_t st_nlink;
+    uint64_t st_rdev;
+    uint64_t st_size;
+    uint64_t st_blksize;
+    uint64_t st_blocks;
+    uint64_t st_atime_sec;
+    uint64_t st_atime_nsec;
+    uint64_t st_mtime_sec;
+    uint64_t st_mtime_nsec;
+    uint64_t st_ctime_sec;
+    uint64_t st_ctime_nsec;
+    uint64_t st_btime_sec;
+    uint64_t st_btime_nsec;
+    uint64_t st_gen;
+    uint64_t st_data_version;
+} V9fsStatDotl;
+
+typedef struct V9fsStatStateDotl {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsStatDotl v9stat_dotl;
+    struct stat stbuf;
+} V9fsStatStateDotl;
+
+
+typedef struct V9fsWalkState {
+    V9fsPDU *pdu;
+    size_t offset;
+    uint16_t nwnames;
+    int name_idx;
+    V9fsQID *qids;
+    V9fsFidState *fidp;
+    V9fsFidState *newfidp;
+    V9fsString path;
+    V9fsString *wnames;
+    struct stat stbuf;
+} V9fsWalkState;
+
+typedef struct V9fsOpenState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t mode;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    struct stat stbuf;
+    int iounit;
+} V9fsOpenState;
+
+typedef struct V9fsReadState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t count;
+    int32_t total;
+    int64_t off;
+    V9fsFidState *fidp;
+    struct iovec iov[128]; /* FIXME: bad, bad, bad */
+    struct iovec *sg;
+    off_t dir_pos;
+    struct dirent *dent;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsStat v9stat;
+    int32_t len;
+    int32_t cnt;
+    int32_t max_count;
+} V9fsReadState;
+
+typedef struct V9fsWriteState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t len;
+    int32_t count;
+    int32_t total;
+    int64_t off;
+    V9fsFidState *fidp;
+    struct iovec iov[128]; /* FIXME: bad, bad, bad */
+    struct iovec *sg;
+    int cnt;
+} V9fsWriteState;
+
+typedef struct V9fsRemoveState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *fidp;
+} V9fsRemoveState;
+
+typedef struct V9fsWstatState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    int16_t unused;
+    V9fsStat v9stat;
+    V9fsFidState *fidp;
+    struct stat stbuf;
+} V9fsWstatState;
+
+typedef struct V9fsSymlinkState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsString name;
+    V9fsString symname;
+    V9fsString fullname;
+    V9fsFidState *dfidp;
+    V9fsQID qid;
+    struct stat stbuf;
+} V9fsSymlinkState;
+
+typedef struct V9fsIattr
+{
+    int32_t valid;
+    int32_t mode;
+    int32_t uid;
+    int32_t gid;
+    int64_t size;
+    int64_t atime_sec;
+    int64_t atime_nsec;
+    int64_t mtime_sec;
+    int64_t mtime_nsec;
+} V9fsIattr;
+
+typedef struct V9fsSetattrState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsIattr v9iattr;
+    V9fsFidState *fidp;
+} V9fsSetattrState;
+
+struct virtio_9p_config
+{
+    /* number of characters in tag */
+    uint16_t tag_len;
+    /* Variable size tag name */
+    uint8_t tag[0];
+} __attribute__((packed));
+
+typedef struct V9fsStatfs
+{
+    uint32_t f_type;
+    uint32_t f_bsize;
+    uint64_t f_blocks;
+    uint64_t f_bfree;
+    uint64_t f_bavail;
+    uint64_t f_files;
+    uint64_t f_ffree;
+    uint64_t fsid_val;
+    uint32_t f_namelen;
+} V9fsStatfs;
+
+typedef struct V9fsStatfsState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t fid;
+    V9fsStatfs v9statfs;
+    V9fsFidState *fidp;
+    struct statfs stbuf;
+} V9fsStatfsState;
+
+typedef struct V9fsMkState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsQID qid;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString fullname;
+} V9fsMkState;
+
+typedef struct V9fsRenameState {
+    V9fsPDU *pdu;
+    V9fsFidState *fidp;
+    size_t offset;
+    int32_t newdirfid;
+    V9fsString name;
+} V9fsRenameState;
+
+typedef struct V9fsXattrState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *file_fidp;
+    V9fsFidState *xattr_fidp;
+    V9fsString name;
+    int64_t size;
+    int flags;
+    void *value;
+} V9fsXattrState;
+
+#define P9_LOCK_SUCCESS 0
+#define P9_LOCK_BLOCKED 1
+#define P9_LOCK_ERROR 2
+#define P9_LOCK_GRACE 3
+
+#define P9_LOCK_FLAGS_BLOCK 1
+#define P9_LOCK_FLAGS_RECLAIM 2
+
+typedef struct V9fsFlock
+{
+    uint8_t type;
+    uint32_t flags;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    V9fsString client_id;
+} V9fsFlock;
+
+typedef struct V9fsLockState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    int8_t status;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsFlock *flock;
+} V9fsLockState;
+
+typedef struct V9fsGetlock
+{
+    uint8_t type;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    V9fsString client_id;
+} V9fsGetlock;
+
+typedef struct V9fsGetlockState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsGetlock *glock;
+} V9fsGetlockState;
+
+typedef struct V9fsReadLinkState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsString target;
+} V9fsReadLinkState;
+
+size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
+                      size_t offset, size_t size, int pack);
+
+static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
+                        size_t offset, size_t size)
+{
+    return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
+}
+
+#endif
index 8071e7bebaf67cb312fe05b88231f8e9a02f97b3..ad40fb4c3cdca06afcd88d61c1a4d5272bc64ecf 100644 (file)
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -15,6 +15,7 @@
  * 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 "sysemu.h"
 #include "hw.h"
 #include "pc.h"
 #include "acpi.h"
@@ -197,3 +198,199 @@ out:
     }
     return -1;
 }
+
+/* ACPI PM1a EVT */
+uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time)
+{
+    int64_t d = acpi_pm_tmr_get_clock();
+    if (d >= overflow_time) {
+        pm1->sts |= ACPI_BITMASK_TIMER_STATUS;
+    }
+    return pm1->sts;
+}
+
+void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val)
+{
+    uint16_t pm1_sts = acpi_pm1_evt_get_sts(pm1, tmr->overflow_time);
+    if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
+        /* if TMRSTS is reset, then compute the new overflow time */
+        acpi_pm_tmr_calc_overflow_time(tmr);
+    }
+    pm1->sts &= ~val;
+}
+
+void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr)
+{
+    if (!pm1) {
+        qemu_system_shutdown_request();
+    } else if (pm1->en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
+        pm1->sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
+        tmr->update_sci(tmr);
+    }
+}
+
+void acpi_pm1_evt_reset(ACPIPM1EVT *pm1)
+{
+    pm1->sts = 0;
+    pm1->en = 0;
+}
+
+/* ACPI PM_TMR */
+void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable)
+{
+    int64_t expire_time;
+
+    /* schedule a timer interruption if needed */
+    if (enable) {
+        expire_time = muldiv64(tmr->overflow_time, get_ticks_per_sec(),
+                               PM_TIMER_FREQUENCY);
+        qemu_mod_timer(tmr->timer, expire_time);
+    } else {
+        qemu_del_timer(tmr->timer);
+    }
+}
+
+void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr)
+{
+    int64_t d = acpi_pm_tmr_get_clock();
+    tmr->overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
+}
+
+uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr)
+{
+    uint32_t d = acpi_pm_tmr_get_clock();;
+    return d & 0xffffff;
+}
+
+static void acpi_pm_tmr_timer(void *opaque)
+{
+    ACPIPMTimer *tmr = opaque;
+    tmr->update_sci(tmr);
+}
+
+void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci)
+{
+    tmr->update_sci = update_sci;
+    tmr->timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, tmr);
+}
+
+void acpi_pm_tmr_reset(ACPIPMTimer *tmr)
+{
+    tmr->overflow_time = 0;
+    qemu_del_timer(tmr->timer);
+}
+
+/* ACPI PM1aCNT */
+void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3)
+{
+    pm1_cnt->cmos_s3 = cmos_s3;
+}
+
+void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val)
+{
+    pm1_cnt->cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
+
+    if (val & ACPI_BITMASK_SLEEP_ENABLE) {
+        /* change suspend type */
+        uint16_t sus_typ = (val >> 10) & 7;
+        switch(sus_typ) {
+        case 0: /* soft power off */
+            qemu_system_shutdown_request();
+            break;
+        case 1:
+            /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
+               Pretend that resume was caused by power button */
+            pm1a->sts |=
+                (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
+            qemu_system_reset_request();
+            qemu_irq_raise(pm1_cnt->cmos_s3);
+        default:
+            break;
+        }
+    }
+}
+
+void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt,
+                         bool sci_enable, bool sci_disable)
+{
+    /* ACPI specs 3.0, 4.7.2.5 */
+    if (sci_enable) {
+        pm1_cnt->cnt |= ACPI_BITMASK_SCI_ENABLE;
+    } else if (sci_disable) {
+        pm1_cnt->cnt &= ~ACPI_BITMASK_SCI_ENABLE;
+    }
+}
+
+void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt)
+{
+    pm1_cnt->cnt = 0;
+    if (pm1_cnt->cmos_s3) {
+        qemu_irq_lower(pm1_cnt->cmos_s3);
+    }
+}
+
+/* ACPI GPE */
+void acpi_gpe_init(ACPIGPE *gpe, uint8_t len)
+{
+    gpe->len = len;
+    gpe->sts = qemu_mallocz(len / 2);
+    gpe->en = qemu_mallocz(len / 2);
+}
+
+void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk)
+{
+    gpe->blk = blk;
+}
+
+void acpi_gpe_reset(ACPIGPE *gpe)
+{
+    memset(gpe->sts, 0, gpe->len / 2);
+    memset(gpe->en, 0, gpe->len / 2);
+}
+
+static uint8_t *acpi_gpe_ioport_get_ptr(ACPIGPE *gpe, uint32_t addr)
+{
+    uint8_t *cur = NULL;
+
+    if (addr < gpe->len / 2) {
+        cur = gpe->sts + addr;
+    } else if (addr < gpe->len) {
+        cur = gpe->en + addr - gpe->len / 2;
+    } else {
+        abort();
+    }
+
+    return cur;
+}
+
+void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val)
+{
+    uint8_t *cur;
+
+    addr -= gpe->blk;
+    cur = acpi_gpe_ioport_get_ptr(gpe, addr);
+    if (addr < gpe->len / 2) {
+        /* GPE_STS */
+        *cur = (*cur) & ~val;
+    } else if (addr < gpe->len) {
+        /* GPE_EN */
+        *cur = val;
+    } else {
+        abort();
+    }
+}
+
+uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr)
+{
+    uint8_t *cur;
+    uint32_t val;
+
+    addr -= gpe->blk;
+    cur = acpi_gpe_ioport_get_ptr(gpe, addr);
+    val = 0;
+    if (cur != NULL) {
+        val = *cur;
+    }
+
+    return val;
+}
index 5949958067d4c220fcdc92be5d9306699bb96ec6..c141e65f4f61419c57b4450273294dbc6c0374a0 100644 (file)
--- a/hw/acpi.h
+++ b/hw/acpi.h
 #define ACPI_BITMASK_ARB_DISABLE                0x0001
 
 /* PM_TMR */
+struct ACPIPMTimer;
+typedef struct ACPIPMTimer ACPIPMTimer;
+
+typedef void (*acpi_update_sci_fn)(ACPIPMTimer *tmr);
+
+struct ACPIPMTimer {
+    QEMUTimer *timer;
+    int64_t overflow_time;
+
+    acpi_update_sci_fn update_sci;
+};
+
+void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable);
+void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr);
+uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr);
+void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci);
+void acpi_pm_tmr_reset(ACPIPMTimer *tmr);
+
+#include "qemu-timer.h"
+static inline int64_t acpi_pm_tmr_get_clock(void)
+{
+    return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
+                    get_ticks_per_sec());
+}
+
+/* PM1a_EVT: piix and ich9 don't implement PM1b. */
+struct ACPIPM1EVT
+{
+    uint16_t sts;
+    uint16_t en;
+};
+typedef struct ACPIPM1EVT ACPIPM1EVT;
+
+uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time);
+void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val);
+void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr);
+void acpi_pm1_evt_reset(ACPIPM1EVT *pm1);
+
+/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
+struct ACPIPM1CNT {
+    uint16_t cnt;
+
+    qemu_irq cmos_s3;
+};
+typedef struct ACPIPM1CNT ACPIPM1CNT;
+
+void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3);
+void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val);
+void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt,
+                         bool sci_enable, bool sci_disable);
+void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt);
+
+/* GPE0 */
+struct ACPIGPE {
+    uint32_t blk;
+    uint8_t len;
+
+    uint8_t *sts;
+    uint8_t *en;
+};
+typedef struct ACPIGPE ACPIGPE;
+
+void acpi_gpe_init(ACPIGPE *gpe, uint8_t len);
+void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk);
+void acpi_gpe_reset(ACPIGPE *gpe);
+
+void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val);
+uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr);
 
 #endif /* !QEMU_HW_ACPI_H */
index 0b2bc97cf1b030c356bf4b1a391ae64b63011c8e..96f522233a8c79af918f22c8fefeb12eca9e44c1 100644 (file)
 #define ACPI_DBG_IO_ADDR  0xb044
 
 #define GPE_BASE 0xafe0
+#define GPE_LEN 4
 #define PCI_BASE 0xae00
 #define PCI_EJ_BASE 0xae08
 #define PCI_RMV_BASE 0xae0c
 
 #define PIIX4_PCI_HOTPLUG_STATUS 2
 
-struct gpe_regs {
-    uint16_t sts; /* status */
-    uint16_t en;  /* enabled */
-};
-
 struct pci_status {
     uint32_t up;
     uint32_t down;
@@ -54,25 +50,22 @@ struct pci_status {
 typedef struct PIIX4PMState {
     PCIDevice dev;
     IORange ioport;
-    uint16_t pmsts;
-    uint16_t pmen;
-    uint16_t pmcntrl;
+    ACPIPM1EVT pm1a;
+    ACPIPM1CNT pm1_cnt;
 
     APMState apm;
 
-    QEMUTimer *tmr_timer;
-    int64_t tmr_overflow_time;
+    ACPIPMTimer tmr;
 
     PMSMBus smb;
     uint32_t smb_io_base;
 
     qemu_irq irq;
-    qemu_irq cmos_s3;
     qemu_irq smi_irq;
     int kvm_enabled;
 
     /* for pci hotplug */
-    struct gpe_regs gpe;
+    ACPIGPE gpe;
     struct pci_status pci0_status;
     uint32_t pci0_hotplug_enable;
 } PIIX4PMState;
@@ -82,52 +75,27 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
 #define ACPI_ENABLE 0xf1
 #define ACPI_DISABLE 0xf0
 
-static uint32_t get_pmtmr(PIIX4PMState *s)
-{
-    uint32_t d;
-    d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec());
-    return d & 0xffffff;
-}
-
-static int get_pmsts(PIIX4PMState *s)
-{
-    int64_t d;
-
-    d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
-                 get_ticks_per_sec());
-    if (d >= s->tmr_overflow_time)
-        s->pmsts |= ACPI_BITMASK_TIMER_STATUS;
-    return s->pmsts;
-}
-
 static void pm_update_sci(PIIX4PMState *s)
 {
     int sci_level, pmsts;
-    int64_t expire_time;
 
-    pmsts = get_pmsts(s);
-    sci_level = (((pmsts & s->pmen) &
+    pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
+    sci_level = (((pmsts & s->pm1a.en) &
                   (ACPI_BITMASK_RT_CLOCK_ENABLE |
                    ACPI_BITMASK_POWER_BUTTON_ENABLE |
                    ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
                    ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
-        (((s->gpe.sts & s->gpe.en) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
+        (((s->gpe.sts[0] & s->gpe.en[0]) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
 
     qemu_set_irq(s->irq, sci_level);
     /* schedule a timer interruption if needed */
-    if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
-        !(pmsts & ACPI_BITMASK_TIMER_STATUS)) {
-        expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(),
-                               PM_TIMER_FREQUENCY);
-        qemu_mod_timer(s->tmr_timer, expire_time);
-    } else {
-        qemu_del_timer(s->tmr_timer);
-    }
+    acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
+                       !(pmsts & ACPI_BITMASK_TIMER_STATUS));
 }
 
-static void pm_tmr_timer(void *opaque)
+static void pm_tmr_timer(ACPIPMTimer *tmr)
 {
-    PIIX4PMState *s = opaque;
+    PIIX4PMState *s = container_of(tmr, PIIX4PMState, tmr);
     pm_update_sci(s);
 }
 
@@ -143,54 +111,21 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
 
     switch(addr) {
     case 0x00:
-        {
-            int64_t d;
-            int pmsts;
-            pmsts = get_pmsts(s);
-            if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) {
-                /* if TMRSTS is reset, then compute the new overflow time */
-                d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
-                             get_ticks_per_sec());
-                s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
-            }
-            s->pmsts &= ~val;
-            pm_update_sci(s);
-        }
+        acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val);
+        pm_update_sci(s);
         break;
     case 0x02:
-        s->pmen = val;
+        s->pm1a.en = val;
         pm_update_sci(s);
         break;
     case 0x04:
-        {
-            int sus_typ;
-            s->pmcntrl = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
-            if (val & ACPI_BITMASK_SLEEP_ENABLE) {
-                /* change suspend type */
-                sus_typ = (val >> 10) & 7;
-                switch(sus_typ) {
-                case 0: /* soft power off */
-                    qemu_system_shutdown_request();
-                    break;
-                case 1:
-                    /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
-                       Pretend that resume was caused by power button */
-                    s->pmsts |= (ACPI_BITMASK_WAKE_STATUS |
-                                 ACPI_BITMASK_POWER_BUTTON_STATUS);
-                    qemu_system_reset_request();
-                    if (s->cmos_s3) {
-                        qemu_irq_raise(s->cmos_s3);
-                    }
-                default:
-                    break;
-                }
-            }
-        }
+        acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val);
         break;
     default:
         break;
     }
-    PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val);
+    PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", (unsigned int)addr,
+                  (unsigned int)val);
 }
 
 static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
@@ -201,22 +136,22 @@ static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
 
     switch(addr) {
     case 0x00:
-        val = get_pmsts(s);
+        val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
         break;
     case 0x02:
-        val = s->pmen;
+        val = s->pm1a.en;
         break;
     case 0x04:
-        val = s->pmcntrl;
+        val = s->pm1_cnt.cnt;
         break;
     case 0x08:
-        val = get_pmtmr(s);
+        val = acpi_pm_tmr_get(&s->tmr);
         break;
     default:
         val = 0;
         break;
     }
-    PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
+    PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", (unsigned int)addr, val);
     *data = val;
 }
 
@@ -230,11 +165,7 @@ static void apm_ctrl_changed(uint32_t val, void *arg)
     PIIX4PMState *s = arg;
 
     /* ACPI specs 3.0, 4.7.2.5 */
-    if (val == ACPI_ENABLE) {
-        s->pmcntrl |= ACPI_BITMASK_SCI_ENABLE;
-    } else if (val == ACPI_DISABLE) {
-        s->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE;
-    }
+    acpi_pm1_cnt_update(&s->pm1_cnt, val == ACPI_ENABLE, val == ACPI_DISABLE);
 
     if (s->dev.config[0x5b] & (1 << 1)) {
         if (s->smi_irq) {
@@ -279,14 +210,25 @@ static int vmstate_acpi_post_load(void *opaque, int version_id)
     return 0;
 }
 
+#define VMSTATE_GPE_ARRAY(_field, _state)                            \
+ {                                                                   \
+     .name       = (stringify(_field)),                              \
+     .version_id = 0,                                                \
+     .num        = GPE_LEN,                                          \
+     .info       = &vmstate_info_uint16,                             \
+     .size       = sizeof(uint16_t),                                 \
+     .flags      = VMS_ARRAY | VMS_POINTER,                          \
+     .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
+ }
+
 static const VMStateDescription vmstate_gpe = {
     .name = "gpe",
     .version_id = 1,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField []) {
-        VMSTATE_UINT16(sts, struct gpe_regs),
-        VMSTATE_UINT16(en, struct gpe_regs),
+        VMSTATE_GPE_ARRAY(sts, ACPIGPE),
+        VMSTATE_GPE_ARRAY(en, ACPIGPE),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -311,13 +253,13 @@ static const VMStateDescription vmstate_acpi = {
     .post_load = vmstate_acpi_post_load,
     .fields      = (VMStateField []) {
         VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
-        VMSTATE_UINT16(pmsts, PIIX4PMState),
-        VMSTATE_UINT16(pmen, PIIX4PMState),
-        VMSTATE_UINT16(pmcntrl, PIIX4PMState),
+        VMSTATE_UINT16(pm1a.sts, PIIX4PMState),
+        VMSTATE_UINT16(pm1a.en, PIIX4PMState),
+        VMSTATE_UINT16(pm1_cnt.cnt, PIIX4PMState),
         VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
-        VMSTATE_TIMER(tmr_timer, PIIX4PMState),
-        VMSTATE_INT64(tmr_overflow_time, PIIX4PMState),
-        VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, struct gpe_regs),
+        VMSTATE_TIMER(tmr.timer, PIIX4PMState),
+        VMSTATE_INT64(tmr.overflow_time, PIIX4PMState),
+        VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
         VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
                        struct pci_status),
         VMSTATE_END_OF_LIST()
@@ -363,13 +305,10 @@ static void piix4_reset(void *opaque)
 static void piix4_powerdown(void *opaque, int irq, int power_failing)
 {
     PIIX4PMState *s = opaque;
+    ACPIPM1EVT *pm1a = s? &s->pm1a: NULL;
+    ACPIPMTimer *tmr = s? &s->tmr: NULL;
 
-    if (!s) {
-        qemu_system_shutdown_request();
-    } else if (s->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
-        s->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
-        pm_update_sci(s);
-    }
+    acpi_pm1_evt_power_down(pm1a, tmr);
 }
 
 static int piix4_pm_initfn(PCIDevice *dev)
@@ -413,7 +352,8 @@ static int piix4_pm_initfn(PCIDevice *dev)
     register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb);
     register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb);
 
-    s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s);
+    acpi_pm_tmr_init(&s->tmr, pm_tmr_timer);
+    acpi_gpe_init(&s->gpe, GPE_LEN);
 
     qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1);
 
@@ -436,7 +376,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
 
     s = DO_UPCAST(PIIX4PMState, dev, dev);
     s->irq = sci_irq;
-    s->cmos_s3 = cmos_s3;
+    acpi_pm1_cnt_init(&s->pm1_cnt, cmos_s3);
     s->smi_irq = smi_irq;
     s->kvm_enabled = kvm_enabled;
 
@@ -467,74 +407,20 @@ static void piix4_pm_register(void)
 
 device_init(piix4_pm_register);
 
-static uint32_t gpe_read_val(uint16_t val, uint32_t addr)
-{
-    if (addr & 1)
-        return (val >> 8) & 0xff;
-    return val & 0xff;
-}
-
 static uint32_t gpe_readb(void *opaque, uint32_t addr)
 {
-    uint32_t val = 0;
     PIIX4PMState *s = opaque;
-    struct gpe_regs *g = &s->gpe;
-
-    switch (addr) {
-        case GPE_BASE:
-        case GPE_BASE + 1:
-            val = gpe_read_val(g->sts, addr);
-            break;
-        case GPE_BASE + 2:
-        case GPE_BASE + 3:
-            val = gpe_read_val(g->en, addr);
-            break;
-        default:
-            break;
-    }
+    uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr);
 
     PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
     return val;
 }
 
-static void gpe_write_val(uint16_t *cur, int addr, uint32_t val)
-{
-    if (addr & 1)
-        *cur = (*cur & 0xff) | (val << 8);
-    else
-        *cur = (*cur & 0xff00) | (val & 0xff);
-}
-
-static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val)
-{
-    uint16_t x1, x0 = val & 0xff;
-    int shift = (addr & 1) ? 8 : 0;
-
-    x1 = (*cur >> shift) & 0xff;
-
-    x1 = x1 & ~x0;
-
-    *cur = (*cur & (0xff << (8 - shift))) | (x1 << shift);
-}
-
 static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
     PIIX4PMState *s = opaque;
-    struct gpe_regs *g = &s->gpe;
-
-    switch (addr) {
-        case GPE_BASE:
-        case GPE_BASE + 1:
-            gpe_reset_val(&g->sts, addr, val);
-            break;
-        case GPE_BASE + 2:
-        case GPE_BASE + 3:
-            gpe_write_val(&g->en, addr, val);
-            break;
-        default:
-            break;
-    }
 
+    acpi_gpe_ioport_writeb(&s->gpe, addr, val);
     pm_update_sci(s);
 
     PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
@@ -617,8 +503,9 @@ 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, 4, 1, gpe_writeb, s);
-    register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, s);
+    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->gpe, GPE_BASE);
 
     register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
     register_ioport_read(PCI_BASE, 8, 4,  pcihotplug_read, pci0_status);
@@ -634,13 +521,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
 
 static void enable_device(PIIX4PMState *s, int slot)
 {
-    s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
+    s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
     s->pci0_status.up |= (1 << slot);
 }
 
 static void disable_device(PIIX4PMState *s, int slot)
 {
-    s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
+    s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
     s->pci0_status.down |= (1 << slot);
 }
 
index 99b30f6bc7dbeb6967b9e5bfb9c8aa3763e2353c..7499cdcef8b04b77f7c13505a167fa5e16226ea5 100644 (file)
--- a/hw/adb.c
+++ b/hw/adb.c
@@ -261,30 +261,19 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
     return olen;
 }
 
-static void adb_kbd_save(QEMUFile *f, void *opaque)
-{
-    KBDState *s = (KBDState *)opaque;
-
-    qemu_put_buffer(f, s->data, sizeof(s->data));
-    qemu_put_sbe32s(f, &s->rptr);
-    qemu_put_sbe32s(f, &s->wptr);
-    qemu_put_sbe32s(f, &s->count);
-}
-
-static int adb_kbd_load(QEMUFile *f, void *opaque, int version_id)
-{
-    KBDState *s = (KBDState *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    qemu_get_buffer(f, s->data, sizeof(s->data));
-    qemu_get_sbe32s(f, &s->rptr);
-    qemu_get_sbe32s(f, &s->wptr);
-    qemu_get_sbe32s(f, &s->count);
-
-    return 0;
-}
+static const VMStateDescription vmstate_adb_kbd = {
+    .name = "adb_kbd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_BUFFER(data, KBDState),
+        VMSTATE_INT32(rptr, KBDState),
+        VMSTATE_INT32(wptr, KBDState),
+        VMSTATE_INT32(count, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int adb_kbd_reset(ADBDevice *d)
 {
@@ -305,8 +294,7 @@ void adb_kbd_init(ADBBusState *bus)
     d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
                             adb_kbd_reset, s);
     qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
-    register_savevm(NULL, "adb_kbd", -1, 1, adb_kbd_save,
-                    adb_kbd_load, s);
+    vmstate_register(NULL, -1, &vmstate_adb_kbd, s);
 }
 
 /***************************************************************/
@@ -439,32 +427,20 @@ static int adb_mouse_reset(ADBDevice *d)
     return 0;
 }
 
-static void adb_mouse_save(QEMUFile *f, void *opaque)
-{
-    MouseState *s = (MouseState *)opaque;
-
-    qemu_put_sbe32s(f, &s->buttons_state);
-    qemu_put_sbe32s(f, &s->last_buttons_state);
-    qemu_put_sbe32s(f, &s->dx);
-    qemu_put_sbe32s(f, &s->dy);
-    qemu_put_sbe32s(f, &s->dz);
-}
-
-static int adb_mouse_load(QEMUFile *f, void *opaque, int version_id)
-{
-    MouseState *s = (MouseState *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    qemu_get_sbe32s(f, &s->buttons_state);
-    qemu_get_sbe32s(f, &s->last_buttons_state);
-    qemu_get_sbe32s(f, &s->dx);
-    qemu_get_sbe32s(f, &s->dy);
-    qemu_get_sbe32s(f, &s->dz);
-
-    return 0;
-}
+static const VMStateDescription vmstate_adb_mouse = {
+    .name = "adb_mouse",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(buttons_state, MouseState),
+        VMSTATE_INT32(last_buttons_state, MouseState),
+        VMSTATE_INT32(dx, MouseState),
+        VMSTATE_INT32(dy, MouseState),
+        VMSTATE_INT32(dz, MouseState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 void adb_mouse_init(ADBBusState *bus)
 {
@@ -475,6 +451,5 @@ void adb_mouse_init(ADBBusState *bus)
     d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
                             adb_mouse_reset, s);
     qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse");
-    register_savevm(NULL, "adb_mouse", -1, 1, adb_mouse_save,
-                    adb_mouse_load, s);
+    vmstate_register(NULL, -1, &vmstate_adb_mouse, s);
 }
index b3bbeaf68e0cacc3df45661e04d3c5088521e0fd..9c58a5f59f969d6a5ee8d8eb59d4f625b1cb1c4d 100644 (file)
@@ -105,35 +105,30 @@ static void ads7846_ts_event(void *opaque,
     }
 }
 
-static void ads7846_save(QEMUFile *f, void *opaque)
+static int ads7856_post_load(void *opaque, int version_id)
 {
-    ADS7846State *s = (ADS7846State *) opaque;
-    int i;
-
-    for (i = 0; i < 8; i ++)
-        qemu_put_be32(f, s->input[i]);
-    qemu_put_be32(f, s->noise);
-    qemu_put_be32(f, s->cycle);
-    qemu_put_be32(f, s->output);
-}
-
-static int ads7846_load(QEMUFile *f, void *opaque, int version_id)
-{
-    ADS7846State *s = (ADS7846State *) opaque;
-    int i;
-
-    for (i = 0; i < 8; i ++)
-        s->input[i] = qemu_get_be32(f);
-    s->noise = qemu_get_be32(f);
-    s->cycle = qemu_get_be32(f);
-    s->output = qemu_get_be32(f);
+    ADS7846State *s = opaque;
 
     s->pressure = 0;
     ads7846_int_update(s);
-
     return 0;
 }
 
+static const VMStateDescription vmstate_ads7846 = {
+    .name = "ads7846",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = ads7856_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
+        VMSTATE_INT32(noise, ADS7846State),
+        VMSTATE_INT32(cycle, ADS7846State),
+        VMSTATE_INT32(output, ADS7846State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static int ads7846_init(SSISlave *dev)
 {
     ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
@@ -151,7 +146,7 @@ static int ads7846_init(SSISlave *dev)
 
     ads7846_int_update(s);
 
-    register_savevm(NULL, "ads7846", -1, 0, ads7846_save, ads7846_load, s);
+    vmstate_register(NULL, -1, &vmstate_ads7846, s);
     return 0;
 }
 
index b9f19a9944a20c209898238f4c64652a0af32ae1..42a0163fbd2d4c9487148a4a5c7bd95b8636d2a2 100644 (file)
@@ -9,7 +9,6 @@
 #include "hw.h"
 #include "pc.h"
 #include "mcf.h"
-#include "sysemu.h"
 #include "boards.h"
 #include "loader.h"
 #include "elf.h"
index 41e99d1332233bec465b82599c85273fb2db97bf..bfac982e6558e25a10bfb2f7aa04708358dce979 100644 (file)
@@ -15,7 +15,7 @@
 
 #define KERNEL_ARGS_ADDR 0x100
 #define KERNEL_LOAD_ADDR 0x00010000
-#define INITRD_LOAD_ADDR 0x00800000
+#define INITRD_LOAD_ADDR 0x00d00000
 
 /* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
 static uint32_t bootloader[] = {
index 82f05dec84fa523d39f1bb13be77878b5c6c3150..dac9e70750143faae625e9ba55547bb003ef5f8a 100644 (file)
@@ -140,28 +140,19 @@ static void arm_timer_tick(void *opaque)
     arm_timer_update(s);
 }
 
-static void arm_timer_save(QEMUFile *f, void *opaque)
-{
-    arm_timer_state *s = (arm_timer_state *)opaque;
-    qemu_put_be32(f, s->control);
-    qemu_put_be32(f, s->limit);
-    qemu_put_be32(f, s->int_level);
-    qemu_put_ptimer(f, s->timer);
-}
-
-static int arm_timer_load(QEMUFile *f, void *opaque, int version_id)
-{
-    arm_timer_state *s = (arm_timer_state *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->control = qemu_get_be32(f);
-    s->limit = qemu_get_be32(f);
-    s->int_level = qemu_get_be32(f);
-    qemu_get_ptimer(f, s->timer);
-    return 0;
-}
+static const VMStateDescription vmstate_arm_timer = {
+    .name = "arm_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(control, arm_timer_state),
+        VMSTATE_UINT32(limit, arm_timer_state),
+        VMSTATE_INT32(int_level, arm_timer_state),
+        VMSTATE_PTIMER(timer, arm_timer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static arm_timer_state *arm_timer_init(uint32_t freq)
 {
@@ -174,7 +165,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq)
 
     bh = qemu_bh_new(arm_timer_tick, s);
     s->timer = ptimer_init(bh);
-    register_savevm(NULL, "arm_timer", -1, 1, arm_timer_save, arm_timer_load, s);
+    vmstate_register(NULL, -1, &vmstate_arm_timer, s);
     return s;
 }
 
@@ -235,24 +226,17 @@ static CPUWriteMemoryFunc * const sp804_writefn[] = {
    sp804_write
 };
 
-static void sp804_save(QEMUFile *f, void *opaque)
-{
-    sp804_state *s = (sp804_state *)opaque;
-    qemu_put_be32(f, s->level[0]);
-    qemu_put_be32(f, s->level[1]);
-}
-
-static int sp804_load(QEMUFile *f, void *opaque, int version_id)
-{
-    sp804_state *s = (sp804_state *)opaque;
 
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->level[0] = qemu_get_be32(f);
-    s->level[1] = qemu_get_be32(f);
-    return 0;
-}
+static const VMStateDescription vmstate_sp804 = {
+    .name = "sp804",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32_ARRAY(level, sp804_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int sp804_init(SysBusDevice *dev)
 {
@@ -271,7 +255,7 @@ static int sp804_init(SysBusDevice *dev)
     iomemtype = cpu_register_io_memory(sp804_readfn,
                                        sp804_writefn, s, DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
-    register_savevm(&dev->qdev, "sp804", -1, 1, sp804_save, sp804_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
     return 0;
 }
 
index 304cd34bc2a007f74d82130531e722d300531667..72d010a63bece880e829d531a0cb87d1f1741a72 100644 (file)
@@ -9,7 +9,6 @@
 
 #include "sysbus.h"
 #include "arm-misc.h"
-#include "sysemu.h"
 #include "loader.h"
 #include "elf.h"
 
index ffe16b8a615f52aa646e4ae585baa1aab465231d..d06eec9b3998fc819cc96de77716112a350b63f1 100644 (file)
@@ -365,30 +365,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
     }
 }
 
-static void nvic_save(QEMUFile *f, void *opaque)
-{
-    nvic_state *s = (nvic_state *)opaque;
-
-    qemu_put_be32(f, s->systick.control);
-    qemu_put_be32(f, s->systick.reload);
-    qemu_put_be64(f, s->systick.tick);
-    qemu_put_timer(f, s->systick.timer);
-}
-
-static int nvic_load(QEMUFile *f, void *opaque, int version_id)
-{
-    nvic_state *s = (nvic_state *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->systick.control = qemu_get_be32(f);
-    s->systick.reload = qemu_get_be32(f);
-    s->systick.tick = qemu_get_be64(f);
-    qemu_get_timer(f, s->systick.timer);
-
-    return 0;
-}
+static const VMStateDescription vmstate_nvic = {
+    .name = "armv7m_nvic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(systick.control, nvic_state),
+        VMSTATE_UINT32(systick.reload, nvic_state),
+        VMSTATE_INT64(systick.tick, nvic_state),
+        VMSTATE_TIMER(systick.timer, nvic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int armv7m_nvic_init(SysBusDevice *dev)
 {
@@ -397,7 +386,7 @@ static int armv7m_nvic_init(SysBusDevice *dev)
     gic_init(&s->gic);
     cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
     s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
-    register_savevm(&dev->qdev, "armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
     return 0;
 }
 
index 57b5e2f04109aae1265d4299754bdf7f3d6b6425..0e2135afd082ae41f07652fffc1abd8ad036f58d 100644 (file)
@@ -26,7 +26,6 @@
 #include "net.h"
 #include "flash.h"
 #include "boards.h"
-#include "sysemu.h"
 #include "etraxfs.h"
 #include "loader.h"
 #include "elf.h"
index 5f329ad13fee46115f486dbfd52e5ac96a9afa25..c5245504af8f55216a2014381c81e214a7d05772 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "console.h"
 #include "devices.h"
 #include "vga_int.h"
index 65ffa37fdf1c1975f087cb4250b9b068f28f8ca5..d135ef47907ffe162b401663466b9c97b3d8ab8c 100644 (file)
@@ -22,7 +22,6 @@
 #include "qemu-char.h"
 #include "qemu-timer.h"
 #include "irq.h"
-#include "sysemu.h"
 #include "net.h"
 #include "bt.h"
 
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
new file mode 100644 (file)
index 0000000..0b07184
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * CCID Card Device. Emulated card.
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This code is licenced under the GNU LGPL, version 2 or later.
+ */
+
+/*
+ * It can be used to provide access to the local hardware in a non exclusive
+ * way, or it can use certificates. It requires the usb-ccid bus.
+ *
+ * Usage 1: standard, mirror hardware reader+card:
+ * qemu .. -usb -device usb-ccid -device ccid-card-emulated
+ *
+ * Usage 2: use certificates, no hardware required
+ * one time: create the certificates:
+ *  for i in 1 2 3; do
+ *      certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
+ *  done
+ * qemu .. -usb -device usb-ccid \
+ *  -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
+ *
+ * If you use a non default db for the certificates you can specify it using
+ * the db parameter.
+ */
+
+#include <eventt.h>
+#include <vevent.h>
+#include <vreader.h>
+#include <vcard_emul.h>
+
+#include "qemu-thread.h"
+#include "qemu-char.h"
+#include "monitor.h"
+#include "hw/ccid.h"
+
+#define DPRINTF(card, lvl, fmt, ...) \
+do {\
+    if (lvl <= card->debug) {\
+        printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
+    } \
+} while (0)
+
+#define EMULATED_DEV_NAME "ccid-card-emulated"
+
+#define BACKEND_NSS_EMULATED_NAME "nss-emulated"
+#define BACKEND_CERTIFICATES_NAME "certificates"
+
+enum {
+    BACKEND_NSS_EMULATED = 1,
+    BACKEND_CERTIFICATES
+};
+
+#define DEFAULT_BACKEND BACKEND_NSS_EMULATED
+
+typedef struct EmulatedState EmulatedState;
+
+enum {
+    EMUL_READER_INSERT = 0,
+    EMUL_READER_REMOVE,
+    EMUL_CARD_INSERT,
+    EMUL_CARD_REMOVE,
+    EMUL_GUEST_APDU,
+    EMUL_RESPONSE_APDU,
+    EMUL_ERROR,
+};
+
+static const char *emul_event_to_string(uint32_t emul_event)
+{
+    switch (emul_event) {
+    case EMUL_READER_INSERT:
+        return "EMUL_READER_INSERT";
+    case EMUL_READER_REMOVE:
+        return "EMUL_READER_REMOVE";
+    case EMUL_CARD_INSERT:
+        return "EMUL_CARD_INSERT";
+    case EMUL_CARD_REMOVE:
+        return "EMUL_CARD_REMOVE";
+    case EMUL_GUEST_APDU:
+        return "EMUL_GUEST_APDU";
+    case EMUL_RESPONSE_APDU:
+        return "EMUL_RESPONSE_APDU";
+    case EMUL_ERROR:
+        return "EMUL_ERROR";
+    }
+    return "UNKNOWN";
+}
+
+typedef struct EmulEvent {
+    QSIMPLEQ_ENTRY(EmulEvent) entry;
+    union {
+        struct {
+            uint32_t type;
+        } gen;
+        struct {
+            uint32_t type;
+            uint64_t code;
+        } error;
+        struct {
+            uint32_t type;
+            uint32_t len;
+            uint8_t data[];
+        } data;
+    } p;
+} EmulEvent;
+
+#define MAX_ATR_SIZE 40
+struct EmulatedState {
+    CCIDCardState base;
+    uint8_t  debug;
+    char    *backend_str;
+    uint32_t backend;
+    char    *cert1;
+    char    *cert2;
+    char    *cert3;
+    char    *db;
+    uint8_t  atr[MAX_ATR_SIZE];
+    uint8_t  atr_length;
+    QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
+    QemuMutex event_list_mutex;
+    VReader *reader;
+    QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
+    QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
+    QemuMutex handle_apdu_mutex;
+    QemuCond handle_apdu_cond;
+    int      pipe[2];
+    int      quit_apdu_thread;
+    QemuMutex apdu_thread_quit_mutex;
+    QemuCond apdu_thread_quit_cond;
+};
+
+static void emulated_apdu_from_guest(CCIDCardState *base,
+    const uint8_t *apdu, uint32_t len)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len);
+
+    assert(event);
+    event->p.data.type = EMUL_GUEST_APDU;
+    event->p.data.len = len;
+    memcpy(event->p.data.data, apdu, len);
+    qemu_mutex_lock(&card->vreader_mutex);
+    QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
+    qemu_mutex_unlock(&card->vreader_mutex);
+    qemu_mutex_lock(&card->handle_apdu_mutex);
+    qemu_cond_signal(&card->handle_apdu_cond);
+    qemu_mutex_unlock(&card->handle_apdu_mutex);
+}
+
+static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+
+    *len = card->atr_length;
+    return card->atr;
+}
+
+static void emulated_push_event(EmulatedState *card, EmulEvent *event)
+{
+    qemu_mutex_lock(&card->event_list_mutex);
+    QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
+    qemu_mutex_unlock(&card->event_list_mutex);
+    if (write(card->pipe[1], card, 1) != 1) {
+        DPRINTF(card, 1, "write to pipe failed\n");
+    }
+}
+
+static void emulated_push_type(EmulatedState *card, uint32_t type)
+{
+    EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent));
+
+    assert(event);
+    event->p.gen.type = type;
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_error(EmulatedState *card, uint64_t code)
+{
+    EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent));
+
+    assert(event);
+    event->p.error.type = EMUL_ERROR;
+    event->p.error.code = code;
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_data_type(EmulatedState *card, uint32_t type,
+    const uint8_t *data, uint32_t len)
+{
+    EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len);
+
+    assert(event);
+    event->p.data.type = type;
+    event->p.data.len = len;
+    memcpy(event->p.data.data, data, len);
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_reader_insert(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_READER_INSERT);
+}
+
+static void emulated_push_reader_remove(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_READER_REMOVE);
+}
+
+static void emulated_push_card_insert(EmulatedState *card,
+    const uint8_t *atr, uint32_t len)
+{
+    emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
+}
+
+static void emulated_push_card_remove(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_CARD_REMOVE);
+}
+
+static void emulated_push_response_apdu(EmulatedState *card,
+    const uint8_t *apdu, uint32_t len)
+{
+    emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
+}
+
+#define APDU_BUF_SIZE 270
+static void *handle_apdu_thread(void* arg)
+{
+    EmulatedState *card = arg;
+    uint8_t recv_data[APDU_BUF_SIZE];
+    int recv_len;
+    VReaderStatus reader_status;
+    EmulEvent *event;
+
+    while (1) {
+        qemu_mutex_lock(&card->handle_apdu_mutex);
+        qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
+        qemu_mutex_unlock(&card->handle_apdu_mutex);
+        if (card->quit_apdu_thread) {
+            card->quit_apdu_thread = 0; /* debugging */
+            break;
+        }
+        qemu_mutex_lock(&card->vreader_mutex);
+        while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
+            event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
+            assert((unsigned long)event > 1000);
+            QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
+            if (event->p.data.type != EMUL_GUEST_APDU) {
+                DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
+                qemu_free(event);
+                continue;
+            }
+            if (card->reader == NULL) {
+                DPRINTF(card, 1, "reader is NULL\n");
+                qemu_free(event);
+                continue;
+            }
+            recv_len = sizeof(recv_data);
+            reader_status = vreader_xfr_bytes(card->reader,
+                    event->p.data.data, event->p.data.len,
+                    recv_data, &recv_len);
+            DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
+            if (reader_status == VREADER_OK) {
+                emulated_push_response_apdu(card, recv_data, recv_len);
+            } else {
+                emulated_push_error(card, reader_status);
+            }
+            qemu_free(event);
+        }
+        qemu_mutex_unlock(&card->vreader_mutex);
+    }
+    qemu_mutex_lock(&card->apdu_thread_quit_mutex);
+    qemu_cond_signal(&card->apdu_thread_quit_cond);
+    qemu_mutex_unlock(&card->apdu_thread_quit_mutex);
+    return NULL;
+}
+
+static void *event_thread(void *arg)
+{
+    int atr_len = MAX_ATR_SIZE;
+    uint8_t atr[MAX_ATR_SIZE];
+    VEvent *event = NULL;
+    EmulatedState *card = arg;
+
+    while (1) {
+        const char *reader_name;
+
+        event = vevent_wait_next_vevent();
+        if (event == NULL || event->type == VEVENT_LAST) {
+            break;
+        }
+        if (event->type != VEVENT_READER_INSERT) {
+            if (card->reader == NULL && event->reader != NULL) {
+                /* Happens after device_add followed by card remove or insert.
+                 * XXX: create synthetic add_reader events if vcard_emul_init
+                 * already called, which happens if device_del and device_add
+                 * are called */
+                card->reader = vreader_reference(event->reader);
+            } else {
+                if (event->reader != card->reader) {
+                    fprintf(stderr,
+                        "ERROR: wrong reader: quiting event_thread\n");
+                    break;
+                }
+            }
+        }
+        switch (event->type) {
+        case VEVENT_READER_INSERT:
+            /* TODO: take a specific reader. i.e. track which reader
+             * we are seeing here, check it is the one we want (the first,
+             * or by a particular name), and ignore if we don't want it.
+             */
+            reader_name = vreader_get_name(event->reader);
+            if (card->reader != NULL) {
+                DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
+                    vreader_get_name(card->reader), reader_name);
+                qemu_mutex_lock(&card->vreader_mutex);
+                vreader_free(card->reader);
+                qemu_mutex_unlock(&card->vreader_mutex);
+                emulated_push_reader_remove(card);
+            }
+            qemu_mutex_lock(&card->vreader_mutex);
+            DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
+            card->reader = vreader_reference(event->reader);
+            qemu_mutex_unlock(&card->vreader_mutex);
+            emulated_push_reader_insert(card);
+            break;
+        case VEVENT_READER_REMOVE:
+            DPRINTF(card, 2, " READER REMOVE: %s\n",
+                    vreader_get_name(event->reader));
+            qemu_mutex_lock(&card->vreader_mutex);
+            vreader_free(card->reader);
+            card->reader = NULL;
+            qemu_mutex_unlock(&card->vreader_mutex);
+            emulated_push_reader_remove(card);
+            break;
+        case VEVENT_CARD_INSERT:
+            /* get the ATR (intended as a response to a power on from the
+             * reader */
+            atr_len = MAX_ATR_SIZE;
+            vreader_power_on(event->reader, atr, &atr_len);
+            card->atr_length = (uint8_t)atr_len;
+            DPRINTF(card, 2, " CARD INSERT\n");
+            emulated_push_card_insert(card, atr, atr_len);
+            break;
+        case VEVENT_CARD_REMOVE:
+            DPRINTF(card, 2, " CARD REMOVE\n");
+            emulated_push_card_remove(card);
+            break;
+        case VEVENT_LAST: /* quit */
+            vevent_delete(event);
+            return NULL;
+            break;
+        default:
+            break;
+        }
+        vevent_delete(event);
+    }
+    return NULL;
+}
+
+static void pipe_read(void *opaque)
+{
+    EmulatedState *card = opaque;
+    EmulEvent *event, *next;
+    char dummy;
+    int len;
+
+    do {
+        len = read(card->pipe[0], &dummy, sizeof(dummy));
+    } while (len == sizeof(dummy));
+    qemu_mutex_lock(&card->event_list_mutex);
+    QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
+        DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
+        switch (event->p.gen.type) {
+        case EMUL_RESPONSE_APDU:
+            ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
+                event->p.data.len);
+            break;
+        case EMUL_READER_INSERT:
+            ccid_card_ccid_attach(&card->base);
+            break;
+        case EMUL_READER_REMOVE:
+            ccid_card_ccid_detach(&card->base);
+            break;
+        case EMUL_CARD_INSERT:
+            assert(event->p.data.len <= MAX_ATR_SIZE);
+            card->atr_length = event->p.data.len;
+            memcpy(card->atr, event->p.data.data, card->atr_length);
+            ccid_card_card_inserted(&card->base);
+            break;
+        case EMUL_CARD_REMOVE:
+            ccid_card_card_removed(&card->base);
+            break;
+        case EMUL_ERROR:
+            ccid_card_card_error(&card->base, event->p.error.code);
+            break;
+        default:
+            DPRINTF(card, 2, "unexpected event\n");
+            break;
+        }
+        qemu_free(event);
+    }
+    QSIMPLEQ_INIT(&card->event_list);
+    qemu_mutex_unlock(&card->event_list_mutex);
+}
+
+static int init_pipe_signaling(EmulatedState *card)
+{
+    if (pipe(card->pipe) < 0) {
+        DPRINTF(card, 2, "pipe creation failed\n");
+        return -1;
+    }
+    fcntl(card->pipe[0], F_SETFL, O_NONBLOCK);
+    fcntl(card->pipe[1], F_SETFL, O_NONBLOCK);
+    fcntl(card->pipe[0], F_SETOWN, getpid());
+    qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card);
+    return 0;
+}
+
+#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
+#define CERTIFICATES_ARGS_TEMPLATE\
+    "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
+
+static int wrap_vcard_emul_init(VCardEmulOptions *options)
+{
+    static int called;
+    static int options_was_null;
+
+    if (called) {
+        if ((options == NULL) != options_was_null) {
+            printf("%s: warning: running emulated with certificates"
+                   " and emulated side by side is not supported\n",
+                   __func__);
+            return VCARD_EMUL_FAIL;
+        }
+        vcard_emul_replay_insertion_events();
+        return VCARD_EMUL_OK;
+    }
+    options_was_null = (options == NULL);
+    called = 1;
+    return vcard_emul_init(options);
+}
+
+static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
+{
+    char emul_args[200];
+    VCardEmulOptions *options = NULL;
+
+    snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
+        card->db ? card->db : CERTIFICATES_DEFAULT_DB,
+        card->cert1, card->cert2, card->cert3);
+    options = vcard_emul_options(emul_args);
+    if (options == NULL) {
+        printf("%s: warning: not using certificates due to"
+               " initialization error\n", __func__);
+    }
+    return wrap_vcard_emul_init(options);
+}
+
+typedef struct EnumTable {
+    const char *name;
+    uint32_t value;
+} EnumTable;
+
+EnumTable backend_enum_table[] = {
+    {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
+    {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
+    {NULL, 0},
+};
+
+static uint32_t parse_enumeration(char *str,
+    EnumTable *table, uint32_t not_found_value)
+{
+    uint32_t ret = not_found_value;
+
+    while (table->name != NULL) {
+        if (strcmp(table->name, str) == 0) {
+            ret = table->value;
+            break;
+        }
+        table++;
+    }
+    return ret;
+}
+
+static int emulated_initfn(CCIDCardState *base)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    QemuThread thread_id;
+    VCardEmulError ret;
+    EnumTable *ptable;
+
+    QSIMPLEQ_INIT(&card->event_list);
+    QSIMPLEQ_INIT(&card->guest_apdu_list);
+    qemu_mutex_init(&card->event_list_mutex);
+    qemu_mutex_init(&card->vreader_mutex);
+    qemu_mutex_init(&card->handle_apdu_mutex);
+    qemu_cond_init(&card->handle_apdu_cond);
+    card->reader = NULL;
+    card->quit_apdu_thread = 0;
+    if (init_pipe_signaling(card) < 0) {
+        return -1;
+    }
+    card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0);
+    if (card->backend == 0) {
+        printf("unknown backend, must be one of:\n");
+        for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
+            printf("%s\n", ptable->name);
+        }
+        return -1;
+    }
+
+    /* TODO: a passthru backened that works on local machine. third card type?*/
+    if (card->backend == BACKEND_CERTIFICATES) {
+        if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
+            ret = emulated_initialize_vcard_from_certificates(card);
+        } else {
+            printf("%s: you must provide all three certs for"
+                   " certificates backend\n", EMULATED_DEV_NAME);
+            return -1;
+        }
+    } else {
+        if (card->backend != BACKEND_NSS_EMULATED) {
+            printf("%s: bad backend specified. The options are:\n%s (default),"
+                " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME,
+                BACKEND_CERTIFICATES_NAME);
+            return -1;
+        }
+        if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
+            printf("%s: unexpected cert parameters to nss emulated backend\n",
+                   EMULATED_DEV_NAME);
+            return -1;
+        }
+        /* default to mirroring the local hardware readers */
+        ret = wrap_vcard_emul_init(NULL);
+    }
+    if (ret != VCARD_EMUL_OK) {
+        printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
+        return -1;
+    }
+    qemu_thread_create(&thread_id, event_thread, card);
+    qemu_thread_create(&thread_id, handle_apdu_thread, card);
+    return 0;
+}
+
+static int emulated_exitfn(CCIDCardState *base)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
+
+    vevent_queue_vevent(vevent); /* stop vevent thread */
+    qemu_mutex_lock(&card->apdu_thread_quit_mutex);
+    card->quit_apdu_thread = 1; /* stop handle_apdu thread */
+    qemu_cond_signal(&card->handle_apdu_cond);
+    qemu_cond_wait(&card->apdu_thread_quit_cond,
+                      &card->apdu_thread_quit_mutex);
+    /* handle_apdu thread stopped, can destroy all of it's mutexes */
+    qemu_cond_destroy(&card->handle_apdu_cond);
+    qemu_cond_destroy(&card->apdu_thread_quit_cond);
+    qemu_mutex_destroy(&card->apdu_thread_quit_mutex);
+    qemu_mutex_destroy(&card->handle_apdu_mutex);
+    qemu_mutex_destroy(&card->vreader_mutex);
+    qemu_mutex_destroy(&card->event_list_mutex);
+    return 0;
+}
+
+static CCIDCardInfo emulated_card_info = {
+    .qdev.name = EMULATED_DEV_NAME,
+    .qdev.desc = "emulated smartcard",
+    .qdev.size = sizeof(EmulatedState),
+    .initfn = emulated_initfn,
+    .exitfn = emulated_exitfn,
+    .get_atr = emulated_get_atr,
+    .apdu_from_guest = emulated_apdu_from_guest,
+    .qdev.unplug    = qdev_simple_unplug_cb,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
+        DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
+        DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
+        DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
+        DEFINE_PROP_STRING("db", EmulatedState, db),
+        DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void ccid_card_emulated_register_devices(void)
+{
+    ccid_card_qdev_register(&emulated_card_info);
+}
+
+device_init(ccid_card_emulated_register_devices)
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
new file mode 100644 (file)
index 0000000..28eb9d1
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * CCID Passthru Card Device emulation
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-char.h"
+#include "qemu_socket.h"
+#include "monitor.h"
+#include "hw/ccid.h"
+#include "libcacard/vscard_common.h"
+
+#define DPRINTF(card, lvl, fmt, ...)                    \
+do {                                                    \
+    if (lvl <= card->debug) {                           \
+        printf("ccid-card-passthru: " fmt , ## __VA_ARGS__);     \
+    }                                                   \
+} while (0)
+
+#define D_WARN 1
+#define D_INFO 2
+#define D_MORE_INFO 3
+#define D_VERBOSE 4
+
+/* TODO: do we still need this? */
+uint8_t DEFAULT_ATR[] = {
+/*
+ * From some example somewhere
+ * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28
+ */
+
+/* From an Athena smart card */
+ 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21,
+ 0x13, 0x08
+};
+
+
+#define PASSTHRU_DEV_NAME "ccid-card-passthru"
+#define VSCARD_IN_SIZE 65536
+
+/* maximum size of ATR - from 7816-3 */
+#define MAX_ATR_SIZE        40
+
+typedef struct PassthruState PassthruState;
+
+struct PassthruState {
+    CCIDCardState base;
+    CharDriverState *cs;
+    uint8_t  vscard_in_data[VSCARD_IN_SIZE];
+    uint32_t vscard_in_pos;
+    uint32_t vscard_in_hdr;
+    uint8_t  atr[MAX_ATR_SIZE];
+    uint8_t  atr_length;
+    uint8_t  debug;
+};
+
+/*
+ * VSCard protocol over chardev
+ * This code should not depend on the card type.
+ */
+
+static void ccid_card_vscard_send_msg(PassthruState *s,
+        VSCMsgType type, uint32_t reader_id,
+        const uint8_t *payload, uint32_t length)
+{
+    VSCMsgHeader scr_msg_header;
+
+    scr_msg_header.type = htonl(type);
+    scr_msg_header.reader_id = htonl(reader_id);
+    scr_msg_header.length = htonl(length);
+    qemu_chr_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
+    qemu_chr_write(s->cs, payload, length);
+}
+
+static void ccid_card_vscard_send_apdu(PassthruState *s,
+    const uint8_t *apdu, uint32_t length)
+{
+    ccid_card_vscard_send_msg(
+        s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length);
+}
+
+static void ccid_card_vscard_send_error(PassthruState *s,
+                    uint32_t reader_id, VSCErrorCode code)
+{
+    VSCMsgError msg = {.code = htonl(code)};
+
+    ccid_card_vscard_send_msg(
+        s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg));
+}
+
+static void ccid_card_vscard_send_init(PassthruState *s)
+{
+    VSCMsgInit msg = {
+        .version = htonl(VSCARD_VERSION),
+        .magic = VSCARD_MAGIC,
+        .capabilities = {0}
+    };
+
+    ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID,
+                         (uint8_t *)&msg, sizeof(msg));
+}
+
+static int ccid_card_vscard_can_read(void *opaque)
+{
+    PassthruState *card = opaque;
+
+    return VSCARD_IN_SIZE >= card->vscard_in_pos ?
+           VSCARD_IN_SIZE - card->vscard_in_pos : 0;
+}
+
+static void ccid_card_vscard_handle_init(
+    PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init)
+{
+    uint32_t *capabilities;
+    int num_capabilities;
+    int i;
+
+    capabilities = init->capabilities;
+    num_capabilities =
+        1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
+    init->version = ntohl(init->version);
+    for (i = 0 ; i < num_capabilities; ++i) {
+        capabilities[i] = ntohl(capabilities[i]);
+    }
+    if (init->magic != VSCARD_MAGIC) {
+        error_report("wrong magic");
+        /* we can't disconnect the chardev */
+    }
+    if (init->version != VSCARD_VERSION) {
+        DPRINTF(card, D_WARN,
+            "got version %d, have %d", init->version, VSCARD_VERSION);
+    }
+    /* future handling of capabilities, none exist atm */
+    ccid_card_vscard_send_init(card);
+}
+
+static void ccid_card_vscard_handle_message(PassthruState *card,
+    VSCMsgHeader *scr_msg_header)
+{
+    uint8_t *data = (uint8_t *)&scr_msg_header[1];
+
+    switch (scr_msg_header->type) {
+    case VSC_ATR:
+        DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length);
+        if (scr_msg_header->length > MAX_ATR_SIZE) {
+            error_report("ATR size exceeds spec, ignoring");
+            ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+                                        VSC_GENERAL_ERROR);
+        }
+        memcpy(card->atr, data, scr_msg_header->length);
+        card->atr_length = scr_msg_header->length;
+        ccid_card_card_inserted(&card->base);
+        ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+                                    VSC_SUCCESS);
+        break;
+    case VSC_APDU:
+        ccid_card_send_apdu_to_guest(
+            &card->base, data, scr_msg_header->length);
+        break;
+    case VSC_CardRemove:
+        DPRINTF(card, D_INFO, "VSC_CardRemove\n");
+        ccid_card_card_removed(&card->base);
+        ccid_card_vscard_send_error(card,
+            scr_msg_header->reader_id, VSC_SUCCESS);
+        break;
+    case VSC_Init:
+        ccid_card_vscard_handle_init(
+            card, scr_msg_header, (VSCMsgInit *)data);
+        break;
+    case VSC_Error:
+        ccid_card_card_error(&card->base, *(uint32_t *)data);
+        break;
+    case VSC_ReaderAdd:
+        if (ccid_card_ccid_attach(&card->base) < 0) {
+            ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID,
+                                      VSC_CANNOT_ADD_MORE_READERS);
+        } else {
+            ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID,
+                                        VSC_SUCCESS);
+        }
+        break;
+    case VSC_ReaderRemove:
+        ccid_card_ccid_detach(&card->base);
+        ccid_card_vscard_send_error(card,
+            scr_msg_header->reader_id, VSC_SUCCESS);
+        break;
+    default:
+        printf("usb-ccid: chardev: unexpected message of type %X\n",
+               scr_msg_header->type);
+        ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+            VSC_GENERAL_ERROR);
+    }
+}
+
+static void ccid_card_vscard_drop_connection(PassthruState *card)
+{
+    qemu_chr_close(card->cs);
+    card->vscard_in_pos = card->vscard_in_hdr = 0;
+}
+
+static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size)
+{
+    PassthruState *card = opaque;
+    VSCMsgHeader *hdr;
+
+    if (card->vscard_in_pos + size > VSCARD_IN_SIZE) {
+        error_report(
+            "no room for data: pos %d +  size %d > %d. dropping connection.",
+            card->vscard_in_pos, size, VSCARD_IN_SIZE);
+        ccid_card_vscard_drop_connection(card);
+        return;
+    }
+    assert(card->vscard_in_pos < VSCARD_IN_SIZE);
+    assert(card->vscard_in_hdr < VSCARD_IN_SIZE);
+    memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size);
+    card->vscard_in_pos += size;
+    hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
+
+    while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader))
+         &&(card->vscard_in_pos - card->vscard_in_hdr >=
+                                  sizeof(VSCMsgHeader) + ntohl(hdr->length))) {
+        hdr->reader_id = ntohl(hdr->reader_id);
+        hdr->length = ntohl(hdr->length);
+        hdr->type = ntohl(hdr->type);
+        ccid_card_vscard_handle_message(card, hdr);
+        card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader);
+        hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
+    }
+    if (card->vscard_in_hdr == card->vscard_in_pos) {
+        card->vscard_in_pos = card->vscard_in_hdr = 0;
+    }
+}
+
+static void ccid_card_vscard_event(void *opaque, int event)
+{
+    PassthruState *card = opaque;
+
+    switch (event) {
+    case CHR_EVENT_BREAK:
+        card->vscard_in_pos = card->vscard_in_hdr = 0;
+        break;
+    case CHR_EVENT_FOCUS:
+        break;
+    case CHR_EVENT_OPENED:
+        DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
+        break;
+    }
+}
+
+/* End VSCard handling */
+
+static void passthru_apdu_from_guest(
+    CCIDCardState *base, const uint8_t *apdu, uint32_t len)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    if (!card->cs) {
+        printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
+        return;
+    }
+    ccid_card_vscard_send_apdu(card, apdu, len);
+}
+
+static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    *len = card->atr_length;
+    return card->atr;
+}
+
+static int passthru_initfn(CCIDCardState *base)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    card->vscard_in_pos = 0;
+    card->vscard_in_hdr = 0;
+    if (card->cs) {
+        DPRINTF(card, D_INFO, "initing chardev\n");
+        qemu_chr_add_handlers(card->cs,
+            ccid_card_vscard_can_read,
+            ccid_card_vscard_read,
+            ccid_card_vscard_event, card);
+        ccid_card_vscard_send_init(card);
+    } else {
+        error_report("missing chardev");
+        return -1;
+    }
+    assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE);
+    memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR));
+    card->atr_length = sizeof(DEFAULT_ATR);
+    return 0;
+}
+
+static int passthru_exitfn(CCIDCardState *base)
+{
+    return 0;
+}
+
+static VMStateDescription passthru_vmstate = {
+    .name = PASSTHRU_DEV_NAME,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BUFFER(vscard_in_data, PassthruState),
+        VMSTATE_UINT32(vscard_in_pos, PassthruState),
+        VMSTATE_UINT32(vscard_in_hdr, PassthruState),
+        VMSTATE_BUFFER(atr, PassthruState),
+        VMSTATE_UINT8(atr_length, PassthruState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static CCIDCardInfo passthru_card_info = {
+    .qdev.name = PASSTHRU_DEV_NAME,
+    .qdev.desc = "passthrough smartcard",
+    .qdev.size = sizeof(PassthruState),
+    .qdev.vmsd = &passthru_vmstate,
+    .initfn = passthru_initfn,
+    .exitfn = passthru_exitfn,
+    .get_atr = passthru_get_atr,
+    .apdu_from_guest = passthru_apdu_from_guest,
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_CHR("chardev", PassthruState, cs),
+        DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void ccid_card_passthru_register_devices(void)
+{
+    ccid_card_qdev_register(&passthru_card_info);
+}
+
+device_init(ccid_card_passthru_register_devices)
diff --git a/hw/ccid.h b/hw/ccid.h
new file mode 100644 (file)
index 0000000..dbfc13c
--- /dev/null
+++ b/hw/ccid.h
@@ -0,0 +1,59 @@
+/*
+ * CCID Passthru Card Device emulation
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This code is licenced under the GNU LGPL, version 2 or later.
+ */
+
+#ifndef CCID_H
+#define CCID_H
+
+#include "qdev.h"
+
+typedef struct CCIDCardState CCIDCardState;
+typedef struct CCIDCardInfo CCIDCardInfo;
+
+/*
+ * state of the CCID Card device (i.e. hw/ccid-card-*.c)
+ */
+struct CCIDCardState {
+    DeviceState qdev;
+    uint32_t    slot; /* For future use with multiple slot reader. */
+};
+
+/*
+ * callbacks to be used by the CCID device (hw/usb-ccid.c) to call
+ * into the smartcard device (hw/ccid-card-*.c)
+ */
+struct CCIDCardInfo {
+    DeviceInfo qdev;
+    void (*print)(Monitor *mon, CCIDCardState *card, int indent);
+    const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
+    void (*apdu_from_guest)(CCIDCardState *card,
+                            const uint8_t *apdu,
+                            uint32_t len);
+    int (*exitfn)(CCIDCardState *card);
+    int (*initfn)(CCIDCardState *card);
+};
+
+/*
+ * API for smartcard calling the CCID device (used by hw/ccid-card-*.c)
+ */
+void ccid_card_send_apdu_to_guest(CCIDCardState *card,
+                                  uint8_t *apdu,
+                                  uint32_t len);
+void ccid_card_card_removed(CCIDCardState *card);
+void ccid_card_card_inserted(CCIDCardState *card);
+void ccid_card_card_error(CCIDCardState *card, uint64_t error);
+void ccid_card_qdev_register(CCIDCardInfo *card);
+
+/*
+ * support guest visible insertion/removal of ccid devices based on actual
+ * devices connected/removed. Called by card implementation (passthru, local)
+ */
+int ccid_card_ccid_attach(CCIDCardState *card);
+void ccid_card_ccid_detach(CCIDCardState *card);
+
+#endif /* CCID_H */
diff --git a/hw/collie.c b/hw/collie.c
new file mode 100644 (file)
index 0000000..156404d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * SA-1110-based Sharp Zaurus SL-5500 platform.
+ *
+ * Copyright (C) 2011 Dmitry Eremin-Solenikov
+ *
+ * This code is licensed under GNU GPL v2.
+ */
+#include "hw.h"
+#include "sysbus.h"
+#include "boards.h"
+#include "devices.h"
+#include "strongarm.h"
+#include "arm-misc.h"
+#include "flash.h"
+#include "blockdev.h"
+
+static struct arm_boot_info collie_binfo = {
+    .loader_start = SA_SDCS0,
+    .ram_size = 0x20000000,
+};
+
+static void collie_init(ram_addr_t ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    StrongARMState *s;
+    DriveInfo *dinfo;
+    ram_addr_t phys_flash;
+
+    if (!cpu_model) {
+        cpu_model = "sa1110";
+    }
+
+    s = sa1110_init(collie_binfo.ram_size, cpu_model);
+
+    phys_flash = qemu_ram_alloc(NULL, "collie.fl1", 0x02000000);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(SA_CS0, phys_flash,
+                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+
+    phys_flash = qemu_ram_alloc(NULL, "collie.fl2", 0x02000000);
+    dinfo = drive_get(IF_PFLASH, 0, 1);
+    pflash_cfi01_register(SA_CS1, phys_flash,
+                    dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                    512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+
+    sysbus_create_simple("scoop", 0x40800000, NULL);
+
+    collie_binfo.kernel_filename = kernel_filename;
+    collie_binfo.kernel_cmdline = kernel_cmdline;
+    collie_binfo.initrd_filename = initrd_filename;
+    collie_binfo.board_id = 0x208;
+    arm_load_kernel(s->env, &collie_binfo);
+}
+
+static QEMUMachine collie_machine = {
+    .name = "collie",
+    .desc = "Collie PDA (SA-1110)",
+    .init = collie_init,
+};
+
+static void collie_machine_init(void)
+{
+    qemu_register_machine(&collie_machine);
+}
+
+machine_init(collie_machine_init)
index 2ef17f606ce24f4c577c2171f23a753850139bb9..37894f8b53eaeedfff074aba7bb7f6eddc134e31 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include "hw.h"
-#include "sysemu.h"
 #include "loader.h"
 #include "elf.h"
 #include "cris-boot.h"
index 37aa3f47fcc0e9c1530476c64efe60129318d870..065c362aefb9898f1d4447b70e2bddb1bfe9274b 100644 (file)
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -644,80 +644,56 @@ static CPUReadMemoryFunc * const cuda_read[] = {
     &cuda_readl,
 };
 
-static void cuda_save_timer(QEMUFile *f, CUDATimer *s)
+static bool cuda_timer_exist(void *opaque, int version_id)
 {
-    qemu_put_be16s(f, &s->latch);
-    qemu_put_be16s(f, &s->counter_value);
-    qemu_put_sbe64s(f, &s->load_time);
-    qemu_put_sbe64s(f, &s->next_irq_time);
-    if (s->timer)
-        qemu_put_timer(f, s->timer);
-}
-
-static void cuda_save(QEMUFile *f, void *opaque)
-{
-    CUDAState *s = (CUDAState *)opaque;
-
-    qemu_put_ubyte(f, s->b);
-    qemu_put_ubyte(f, s->a);
-    qemu_put_ubyte(f, s->dirb);
-    qemu_put_ubyte(f, s->dira);
-    qemu_put_ubyte(f, s->sr);
-    qemu_put_ubyte(f, s->acr);
-    qemu_put_ubyte(f, s->pcr);
-    qemu_put_ubyte(f, s->ifr);
-    qemu_put_ubyte(f, s->ier);
-    qemu_put_ubyte(f, s->anh);
-    qemu_put_sbe32s(f, &s->data_in_size);
-    qemu_put_sbe32s(f, &s->data_in_index);
-    qemu_put_sbe32s(f, &s->data_out_index);
-    qemu_put_ubyte(f, s->autopoll);
-    qemu_put_buffer(f, s->data_in, sizeof(s->data_in));
-    qemu_put_buffer(f, s->data_out, sizeof(s->data_out));
-    qemu_put_be32s(f, &s->tick_offset);
-    cuda_save_timer(f, &s->timers[0]);
-    cuda_save_timer(f, &s->timers[1]);
-}
+    CUDATimer *s = opaque;
 
-static void cuda_load_timer(QEMUFile *f, CUDATimer *s)
-{
-    qemu_get_be16s(f, &s->latch);
-    qemu_get_be16s(f, &s->counter_value);
-    qemu_get_sbe64s(f, &s->load_time);
-    qemu_get_sbe64s(f, &s->next_irq_time);
-    if (s->timer)
-        qemu_get_timer(f, s->timer);
+    return s->timer != NULL;
 }
 
-static int cuda_load(QEMUFile *f, void *opaque, int version_id)
-{
-    CUDAState *s = (CUDAState *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->b = qemu_get_ubyte(f);
-    s->a = qemu_get_ubyte(f);
-    s->dirb = qemu_get_ubyte(f);
-    s->dira = qemu_get_ubyte(f);
-    s->sr = qemu_get_ubyte(f);
-    s->acr = qemu_get_ubyte(f);
-    s->pcr = qemu_get_ubyte(f);
-    s->ifr = qemu_get_ubyte(f);
-    s->ier = qemu_get_ubyte(f);
-    s->anh = qemu_get_ubyte(f);
-    qemu_get_sbe32s(f, &s->data_in_size);
-    qemu_get_sbe32s(f, &s->data_in_index);
-    qemu_get_sbe32s(f, &s->data_out_index);
-    s->autopoll = qemu_get_ubyte(f);
-    qemu_get_buffer(f, s->data_in, sizeof(s->data_in));
-    qemu_get_buffer(f, s->data_out, sizeof(s->data_out));
-    qemu_get_be32s(f, &s->tick_offset);
-    cuda_load_timer(f, &s->timers[0]);
-    cuda_load_timer(f, &s->timers[1]);
+static const VMStateDescription vmstate_cuda_timer = {
+    .name = "cuda_timer",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT16(latch, CUDATimer),
+        VMSTATE_UINT16(counter_value, CUDATimer),
+        VMSTATE_INT64(load_time, CUDATimer),
+        VMSTATE_INT64(next_irq_time, CUDATimer),
+        VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-    return 0;
-}
+static const VMStateDescription vmstate_cuda = {
+    .name = "cuda",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(a, CUDAState),
+        VMSTATE_UINT8(b, CUDAState),
+        VMSTATE_UINT8(dira, CUDAState),
+        VMSTATE_UINT8(dirb, CUDAState),
+        VMSTATE_UINT8(sr, CUDAState),
+        VMSTATE_UINT8(acr, CUDAState),
+        VMSTATE_UINT8(pcr, CUDAState),
+        VMSTATE_UINT8(ifr, CUDAState),
+        VMSTATE_UINT8(ier, CUDAState),
+        VMSTATE_UINT8(anh, CUDAState),
+        VMSTATE_INT32(data_in_size, CUDAState),
+        VMSTATE_INT32(data_in_index, CUDAState),
+        VMSTATE_INT32(data_out_index, CUDAState),
+        VMSTATE_UINT8(autopoll, CUDAState),
+        VMSTATE_BUFFER(data_in, CUDAState),
+        VMSTATE_BUFFER(data_out, CUDAState),
+        VMSTATE_UINT32(tick_offset, CUDAState),
+        VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1,
+                             vmstate_cuda_timer, CUDATimer),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static void cuda_reset(void *opaque)
 {
@@ -764,6 +740,6 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq)
     s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s);
     *cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s,
                                              DEVICE_NATIVE_ENDIAN);
-    register_savevm(NULL, "cuda", -1, 1, cuda_save, cuda_load, s);
+    vmstate_register(NULL, -1, &vmstate_cuda, s);
     qemu_register_reset(cuda_reset, s);
 }
index 61efb39896a673e842c38dac786ce8545515dd95..cec1cc8e8219489e03a5890b29ce13e1d06fa921 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include "hw.h"
-#include "sysemu.h"
 #include "boards.h"
 #include "loader.h"
 #include "elf.h"
index 55daae0eba5e75902b5d6fd4c71bda3f507d6a3c..f160bfc2ab945030df69feacc8bef5c6f4e50c96 100644 (file)
@@ -517,6 +517,14 @@ txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp)
     return E1000_ICR_TXDW;
 }
 
+static uint64_t tx_desc_base(E1000State *s)
+{
+    uint64_t bah = s->mac_reg[TDBAH];
+    uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
+
+    return (bah << 32) + bal;
+}
+
 static void
 start_xmit(E1000State *s)
 {
@@ -530,7 +538,7 @@ start_xmit(E1000State *s)
     }
 
     while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
-        base = ((uint64_t)s->mac_reg[TDBAH] << 32) + s->mac_reg[TDBAL] +
+        base = tx_desc_base(s) +
                sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
         cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
 
@@ -651,6 +659,14 @@ e1000_can_receive(VLANClientState *nc)
     return (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
 }
 
+static uint64_t rx_desc_base(E1000State *s)
+{
+    uint64_t bah = s->mac_reg[RDBAH];
+    uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
+
+    return (bah << 32) + bal;
+}
+
 static ssize_t
 e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
 {
@@ -700,8 +716,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
         if (desc_size > s->rxbuf_size) {
             desc_size = s->rxbuf_size;
         }
-        base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] +
-               sizeof(desc) * s->mac_reg[RDH];
+        base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
         cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
         desc.special = vlan_special;
         desc.status |= (vlan_status | E1000_RXD_STAT_DD);
@@ -1205,7 +1220,7 @@ static PCIDeviceInfo e1000_info = {
     .qdev.vmsd  = &vmstate_e1000,
     .init       = pci_e1000_init,
     .exit       = pci_e1000_uninit,
-    .romfile    = "pxe-e1000.bin",
+    .romfile    = "pxe-e1000.rom",
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(E1000State, conf),
         DEFINE_PROP_END_OF_LIST(),
index 1781c8ec7c5876785cf4a61094aa616cadd71822..05450e859e933946cac770c951bcb721d9f7447f 100644 (file)
@@ -2174,7 +2174,7 @@ static void eepro100_register_devices(void)
         PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
         /* We use the same rom file for all device ids.
            QEMU fixes the device id during rom load. */
-        pci_dev->romfile = "gpxe-eepro100-80861209.rom";
+        pci_dev->romfile = "pxe-eepro100.rom";
         pci_dev->init = e100_nic_init;
         pci_dev->exit = pci_nic_uninit;
         pci_dev->qdev.props = e100_properties;
index 664b8d9c4d15f73d6db1ebb0f9d2b0857c5daa41..da8adc4d03e2361680165f2ba281bcdee7fb3f08 100644 (file)
@@ -53,18 +53,21 @@ static CPUWriteMemoryFunc * const empty_slot_write[3] = {
 
 void empty_slot_init(target_phys_addr_t addr, uint64_t slot_size)
 {
-    DeviceState *dev;
-    SysBusDevice *s;
-    EmptySlot *e;
+    if (slot_size > 0) {
+        /* Only empty slots larger than 0 byte need handling. */
+        DeviceState *dev;
+        SysBusDevice *s;
+        EmptySlot *e;
 
-    dev = qdev_create(NULL, "empty_slot");
-    s = sysbus_from_qdev(dev);
-    e = FROM_SYSBUS(EmptySlot, s);
-    e->size = slot_size;
+        dev = qdev_create(NULL, "empty_slot");
+        s = sysbus_from_qdev(dev);
+        e = FROM_SYSBUS(EmptySlot, s);
+        e->size = slot_size;
 
-    qdev_init_nofail(dev);
+        qdev_init_nofail(dev);
 
-    sysbus_mmio_map(s, 0, addr);
+        sysbus_mmio_map(s, 0, addr);
+    }
 }
 
 static int empty_slot_init1(SysBusDevice *dev)
index 5ee5f979aac9cc0e72ac5b0252a3e23158ab1795..b84d74a11e1705b08e4620175cb4a131160d83b0 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "sysbus.h"
 #include "boards.h"
-#include "sysemu.h"
 #include "net.h"
 #include "flash.h"
 #include "etraxfs.h"
index 9fdbc750b501e1bf0ed407df1ab9b1b486c10969..edf0360d1bca32d9e66c636fe6acbbc1f537db6e 100644 (file)
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -36,6 +36,7 @@
 #include "qdev-addr.h"
 #include "blockdev.h"
 #include "sysemu.h"
+#include "block_int.h"
 
 /********************************************************/
 /* debug Floppy devices */
@@ -82,6 +83,7 @@ typedef struct FDrive {
     uint8_t max_track;        /* Nb of tracks           */
     uint16_t bps;             /* Bytes per sector       */
     uint8_t ro;               /* Is read-only           */
+    uint8_t media_changed;    /* Is media changed       */
 } FDrive;
 
 static void fd_init(FDrive *drv)
@@ -533,16 +535,63 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
     NULL,
 };
 
+static void fdrive_media_changed_pre_save(void *opaque)
+{
+    FDrive *drive = opaque;
+
+    drive->media_changed = drive->bs->media_changed;
+}
+
+static int fdrive_media_changed_post_load(void *opaque, int version_id)
+{
+    FDrive *drive = opaque;
+
+    if (drive->bs != NULL) {
+        drive->bs->media_changed = drive->media_changed;
+    }
+
+    /* User ejected the floppy when drive->bs == NULL */
+    return 0;
+}
+
+static bool fdrive_media_changed_needed(void *opaque)
+{
+    FDrive *drive = opaque;
+
+    return (drive->bs != NULL && drive->bs->media_changed != 1);
+}
+
+static const VMStateDescription vmstate_fdrive_media_changed = {
+    .name = "fdrive/media_changed",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = fdrive_media_changed_pre_save,
+    .post_load = fdrive_media_changed_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(media_changed, FDrive),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_fdrive = {
     .name = "fdrive",
     .version_id = 1,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
+    .fields      = (VMStateField[]) {
         VMSTATE_UINT8(head, FDrive),
         VMSTATE_UINT8(track, FDrive),
         VMSTATE_UINT8(sect, FDrive),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &vmstate_fdrive_media_changed,
+            .needed = &fdrive_media_changed_needed,
+        } , {
+            /* empty */
+        }
     }
 };
 
diff --git a/hw/file-op-9p.h b/hw/file-op-9p.h
deleted file mode 100644 (file)
index 126e60e..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Virtio 9p
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-#ifndef _FILEOP_H
-#define _FILEOP_H
-#include <sys/types.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <utime.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <sys/vfs.h>
-#define SM_LOCAL_MODE_BITS    0600
-#define SM_LOCAL_DIR_MODE_BITS    0700
-
-typedef enum
-{
-    /*
-     * Server will try to set uid/gid.
-     * On failure ignore the error.
-     */
-    SM_NONE = 0,
-    /*
-     * uid/gid set on fileserver files
-     */
-    SM_PASSTHROUGH = 1,
-    /*
-     * uid/gid part of xattr
-     */
-    SM_MAPPED,
-} SecModel;
-
-typedef struct FsCred
-{
-    uid_t   fc_uid;
-    gid_t   fc_gid;
-    mode_t  fc_mode;
-    dev_t   fc_rdev;
-} FsCred;
-
-struct xattr_operations;
-
-typedef struct FsContext
-{
-    char *fs_root;
-    SecModel fs_sm;
-    uid_t uid;
-    struct xattr_operations **xops;
-} FsContext;
-
-void cred_init(FsCred *);
-
-typedef struct FileOperations
-{
-    int (*lstat)(FsContext *, const char *, struct stat *);
-    ssize_t (*readlink)(FsContext *, const char *, char *, size_t);
-    int (*chmod)(FsContext *, const char *, FsCred *);
-    int (*chown)(FsContext *, const char *, FsCred *);
-    int (*mknod)(FsContext *, const char *, FsCred *);
-    int (*utimensat)(FsContext *, const char *, const struct timespec *);
-    int (*remove)(FsContext *, const char *);
-    int (*symlink)(FsContext *, const char *, const char *, FsCred *);
-    int (*link)(FsContext *, const char *, const char *);
-    int (*setuid)(FsContext *, uid_t);
-    int (*close)(FsContext *, int);
-    int (*closedir)(FsContext *, DIR *);
-    DIR *(*opendir)(FsContext *, const char *);
-    int (*open)(FsContext *, const char *, int);
-    int (*open2)(FsContext *, const char *, int, FsCred *);
-    void (*rewinddir)(FsContext *, DIR *);
-    off_t (*telldir)(FsContext *, DIR *);
-    struct dirent *(*readdir)(FsContext *, DIR *);
-    void (*seekdir)(FsContext *, DIR *, off_t);
-    ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
-    ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
-    int (*mkdir)(FsContext *, const char *, FsCred *);
-    int (*fstat)(FsContext *, int, struct stat *);
-    int (*rename)(FsContext *, const char *, const char *);
-    int (*truncate)(FsContext *, const char *, off_t);
-    int (*fsync)(FsContext *, int, int);
-    int (*statfs)(FsContext *s, const char *path, struct statfs *stbuf);
-    ssize_t (*lgetxattr)(FsContext *, const char *,
-                         const char *, void *, size_t);
-    ssize_t (*llistxattr)(FsContext *, const char *, void *, size_t);
-    int (*lsetxattr)(FsContext *, const char *,
-                     const char *, void *, size_t, int);
-    int (*lremovexattr)(FsContext *, const char *, const char *);
-    void *opaque;
-} FileOperations;
-
-static inline const char *rpath(FsContext *ctx, const char *path)
-{
-    /* FIXME: so wrong... */
-    static char buffer[4096];
-    snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
-    return buffer;
-}
-#endif
index d7d103e66fb62d4deec4471d34deae31becba092..c22e1a922c34fbc430b9c55343f5bd0930f75e7a 100644 (file)
@@ -21,8 +21,8 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
 typedef struct NANDFlashState NANDFlashState;
 NANDFlashState *nand_init(int manf_id, int chip_id);
 void nand_done(NANDFlashState *s);
-void nand_setpins(NANDFlashState *s,
-                int cle, int ale, int ce, int wp, int gnd);
+void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+                  uint8_t ce, uint8_t wp, uint8_t gnd);
 void nand_getpins(NANDFlashState *s, int *rb);
 void nand_setio(NANDFlashState *s, uint8_t value);
 uint8_t nand_getio(NANDFlashState *s);
index 101b150aa55ecaaf45846ee793b85bd7d3dc052a..169a56eb1b4ecbd57a3d2261a6aa324d7b60bda3 100644 (file)
@@ -133,7 +133,7 @@ grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
         break;
     }
 
-    trace_grlib_apbuart_unknown_register("write", addr);
+    trace_grlib_apbuart_writel_unknown(addr, value);
 }
 
 static CPUReadMemoryFunc * const grlib_apbuart_read[] = {
index 596a9000a16107d210ccdfad138d6908e62004f9..99e90336b6202bb39902a94c4b3ee1b6c2da2f2c 100644 (file)
@@ -165,15 +165,15 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
     /* Unit registers */
     switch (addr) {
     case SCALER_OFFSET:
-        trace_grlib_gptimer_readl(-1, "scaler:", unit->scaler);
+        trace_grlib_gptimer_readl(-1, addr, unit->scaler);
         return unit->scaler;
 
     case SCALER_RELOAD_OFFSET:
-        trace_grlib_gptimer_readl(-1, "reload:", unit->reload);
+        trace_grlib_gptimer_readl(-1, addr, unit->reload);
         return unit->reload;
 
     case CONFIG_OFFSET:
-        trace_grlib_gptimer_readl(-1, "config:", unit->config);
+        trace_grlib_gptimer_readl(-1, addr, unit->config);
         return unit->config;
 
     default:
@@ -189,17 +189,16 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
         switch (timer_addr) {
         case COUNTER_OFFSET:
             value = ptimer_get_count(unit->timers[id].ptimer);
-            trace_grlib_gptimer_readl(id, "counter value:", value);
+            trace_grlib_gptimer_readl(id, addr, value);
             return value;
 
         case COUNTER_RELOAD_OFFSET:
             value = unit->timers[id].reload;
-            trace_grlib_gptimer_readl(id, "reload value:", value);
+            trace_grlib_gptimer_readl(id, addr, value);
             return value;
 
         case CONFIG_OFFSET:
-            trace_grlib_gptimer_readl(id, "scaler value:",
-                                      unit->timers[id].config);
+            trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
             return unit->timers[id].config;
 
         default:
@@ -208,7 +207,7 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
 
     }
 
-    trace_grlib_gptimer_unknown_register("read", addr);
+    trace_grlib_gptimer_readl(-1, addr, 0);
     return 0;
 }
 
@@ -226,19 +225,19 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
     case SCALER_OFFSET:
         value &= 0xFFFF; /* clean up the value */
         unit->scaler = value;
-        trace_grlib_gptimer_writel(-1, "scaler:", unit->scaler);
+        trace_grlib_gptimer_writel(-1, addr, unit->scaler);
         return;
 
     case SCALER_RELOAD_OFFSET:
         value &= 0xFFFF; /* clean up the value */
         unit->reload = value;
-        trace_grlib_gptimer_writel(-1, "reload:", unit->reload);
+        trace_grlib_gptimer_writel(-1, addr, unit->reload);
         grlib_gptimer_set_scaler(unit, value);
         return;
 
     case CONFIG_OFFSET:
         /* Read Only (disable timer freeze not supported) */
-        trace_grlib_gptimer_writel(-1, "config (Read Only):", 0);
+        trace_grlib_gptimer_writel(-1, addr, 0);
         return;
 
     default:
@@ -253,18 +252,18 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
         /* GPTimer registers */
         switch (timer_addr) {
         case COUNTER_OFFSET:
-            trace_grlib_gptimer_writel(id, "counter:", value);
+            trace_grlib_gptimer_writel(id, addr, value);
             unit->timers[id].counter = value;
             grlib_gptimer_enable(&unit->timers[id]);
             return;
 
         case COUNTER_RELOAD_OFFSET:
-            trace_grlib_gptimer_writel(id, "reload:", value);
+            trace_grlib_gptimer_writel(id, addr, value);
             unit->timers[id].reload = value;
             return;
 
         case CONFIG_OFFSET:
-            trace_grlib_gptimer_writel(id, "config:", value);
+            trace_grlib_gptimer_writel(id, addr, value);
 
             if (value & GPTIMER_INT_PENDING) {
                 /* clear pending bit */
@@ -297,7 +296,7 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
 
     }
 
-    trace_grlib_gptimer_unknown_register("write", addr);
+    trace_grlib_gptimer_writel(-1, addr, value);
 }
 
 static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
index f47c491a48a8af737f595f36f92635f4d9739f72..b8738fc04d68a3e25bd2d8b727128515b1075d14 100644 (file)
@@ -220,7 +220,7 @@ static uint32_t grlib_irqmp_readl(void *opaque, target_phys_addr_t addr)
         return state->extended[cpu];
     }
 
-    trace_grlib_irqmp_unknown_register("read", addr);
+    trace_grlib_irqmp_readl_unknown(addr);
     return 0;
 }
 
@@ -308,7 +308,7 @@ grlib_irqmp_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
         return;
     }
 
-    trace_grlib_irqmp_unknown_register("write", addr);
+    trace_grlib_irqmp_writel_unknown(addr, value);
 }
 
 static CPUReadMemoryFunc * const grlib_irqmp_read[] = {
index ee63f634cc9b1b4f7a4e2c69843c1bca54b38fbc..853f7e1ee80b74d7f3fe85a2a2c6adffc8066ce6 100644 (file)
@@ -35,7 +35,6 @@
 #include "pxa.h"
 #include "net.h"
 #include "flash.h"
-#include "sysemu.h"
 #include "devices.h"
 #include "boards.h"
 #include "blockdev.h"
index b19b754b31c459e557edf859e3bbead005973b88..5fd71a0f71e258212a07aec75ef369d4b16575b1 100644 (file)
@@ -159,42 +159,31 @@ static void heathrow_pic_set_irq(void *opaque, int num, int level)
     heathrow_pic_update(s);
 }
 
-static void heathrow_pic_save_one(QEMUFile *f, HeathrowPIC *s)
-{
-    qemu_put_be32s(f, &s->events);
-    qemu_put_be32s(f, &s->mask);
-    qemu_put_be32s(f, &s->levels);
-    qemu_put_be32s(f, &s->level_triggered);
-}
-
-static void heathrow_pic_save(QEMUFile *f, void *opaque)
-{
-    HeathrowPICS *s = (HeathrowPICS *)opaque;
-
-    heathrow_pic_save_one(f, &s->pics[0]);
-    heathrow_pic_save_one(f, &s->pics[1]);
-}
-
-static void heathrow_pic_load_one(QEMUFile *f, HeathrowPIC *s)
-{
-    qemu_get_be32s(f, &s->events);
-    qemu_get_be32s(f, &s->mask);
-    qemu_get_be32s(f, &s->levels);
-    qemu_get_be32s(f, &s->level_triggered);
-}
-
-static int heathrow_pic_load(QEMUFile *f, void *opaque, int version_id)
-{
-    HeathrowPICS *s = (HeathrowPICS *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    heathrow_pic_load_one(f, &s->pics[0]);
-    heathrow_pic_load_one(f, &s->pics[1]);
+static const VMStateDescription vmstate_heathrow_pic_one = {
+    .name = "heathrow_pic_one",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(events, HeathrowPIC),
+        VMSTATE_UINT32(mask, HeathrowPIC),
+        VMSTATE_UINT32(levels, HeathrowPIC),
+        VMSTATE_UINT32(level_triggered, HeathrowPIC),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-    return 0;
-}
+static const VMStateDescription vmstate_heathrow_pic = {
+    .name = "heathrow_pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
+                             vmstate_heathrow_pic_one, HeathrowPIC),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static void heathrow_pic_reset_one(HeathrowPIC *s)
 {
@@ -223,8 +212,7 @@ qemu_irq *heathrow_pic_init(int *pmem_index,
     *pmem_index = cpu_register_io_memory(pic_read, pic_write, s,
                                          DEVICE_LITTLE_ENDIAN);
 
-    register_savevm(NULL, "heathrow_pic", -1, 1, heathrow_pic_save,
-                    heathrow_pic_load, s);
+    vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
     qemu_register_reset(heathrow_pic_reset, s);
     return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
 }
diff --git a/hw/hw.h b/hw/hw.h
index 1b090395ab0d30a46ea1b33795d8e7302810cc33..56447a735d07d8ecb8d83a8bcfd65e831f377999 100644 (file)
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -689,6 +689,17 @@ extern const VMStateDescription vmstate_usb_device;
     .offset     = vmstate_offset_macaddr(_state, _field),            \
 }
 
+extern const VMStateDescription vmstate_ptimer;
+
+#define VMSTATE_PTIMER(_field, _state) {                             \
+    .name       = (stringify(_field)),                               \
+    .version_id = (1),                                               \
+    .vmsd       = &vmstate_ptimer,                                   \
+    .size       = sizeof(ptimer_state *),                            \
+    .flags      = VMS_STRUCT|VMS_POINTER,                            \
+    .offset     = vmstate_offset_pointer(_state, _field, ptimer_state), \
+}
+
 /* _f : field name
    _f_n : num of elements field_name
    _n : num of elements
@@ -784,12 +795,6 @@ extern const VMStateDescription vmstate_usb_device;
 #define VMSTATE_TIMER_ARRAY(_f, _s, _n)                              \
     VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
 
-#define VMSTATE_PTIMER_V(_f, _s, _v)                                  \
-    VMSTATE_POINTER(_f, _s, _v, vmstate_info_ptimer, ptimer_state *)
-
-#define VMSTATE_PTIMER(_f, _s)                                        \
-    VMSTATE_PTIMER_V(_f, _s, 0)
-
 #define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v)                         \
     VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
 
index 73fb550574b8106d63d6d7dcab9cc2234056d616..34d9394bcce3803398874f103c307920fa57848f 100644 (file)
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -28,4 +28,7 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
 
 void ide_get_bs(BlockDriverState *bs[], BusState *qbus);
 
+/* ide/core.c */
+void ide_drive_get(DriveInfo **hd, int max_bus);
+
 #endif /* HW_IDE_H */
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
new file mode 100644 (file)
index 0000000..fe2fb0b
--- /dev/null
@@ -0,0 +1,1138 @@
+/*
+ * QEMU ATAPI Emulation
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Openedhand Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/ide/internal.h"
+#include "hw/scsi.h"
+
+static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
+
+static void padstr8(uint8_t *buf, int buf_size, const char *src)
+{
+    int i;
+    for(i = 0; i < buf_size; i++) {
+        if (*src)
+            buf[i] = *src++;
+        else
+            buf[i] = ' ';
+    }
+}
+
+static inline void cpu_to_ube16(uint8_t *buf, int val)
+{
+    buf[0] = val >> 8;
+    buf[1] = val & 0xff;
+}
+
+static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
+{
+    buf[0] = val >> 24;
+    buf[1] = val >> 16;
+    buf[2] = val >> 8;
+    buf[3] = val & 0xff;
+}
+
+static inline int ube16_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 8) | buf[1];
+}
+
+static inline int ube32_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+static void lba_to_msf(uint8_t *buf, int lba)
+{
+    lba += 150;
+    buf[0] = (lba / 75) / 60;
+    buf[1] = (lba / 75) % 60;
+    buf[2] = lba % 75;
+}
+
+static inline int media_present(IDEState *s)
+{
+    return (s->nb_sectors > 0);
+}
+
+/* XXX: DVDs that could fit on a CD will be reported as a CD */
+static inline int media_is_dvd(IDEState *s)
+{
+    return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS);
+}
+
+static inline int media_is_cd(IDEState *s)
+{
+    return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
+}
+
+static void cd_data_to_raw(uint8_t *buf, int lba)
+{
+    /* sync bytes */
+    buf[0] = 0x00;
+    memset(buf + 1, 0xff, 10);
+    buf[11] = 0x00;
+    buf += 12;
+    /* MSF */
+    lba_to_msf(buf, lba);
+    buf[3] = 0x01; /* mode 1 data */
+    buf += 4;
+    /* data */
+    buf += 2048;
+    /* XXX: ECC not computed */
+    memset(buf, 0, 288);
+}
+
+static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
+                           int sector_size)
+{
+    int ret;
+
+    switch(sector_size) {
+    case 2048:
+        ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4);
+        break;
+    case 2352:
+        ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4);
+        if (ret < 0)
+            return ret;
+        cd_data_to_raw(buf, lba);
+        break;
+    default:
+        ret = -EIO;
+        break;
+    }
+    return ret;
+}
+
+void ide_atapi_cmd_ok(IDEState *s)
+{
+    s->error = 0;
+    s->status = READY_STAT | SEEK_STAT;
+    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+    ide_set_irq(s->bus);
+}
+
+void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc)
+{
+#ifdef DEBUG_IDE_ATAPI
+    printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc);
+#endif
+    s->error = sense_key << 4;
+    s->status = READY_STAT | ERR_STAT;
+    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+    s->sense_key = sense_key;
+    s->asc = asc;
+    ide_set_irq(s->bus);
+}
+
+void ide_atapi_io_error(IDEState *s, int ret)
+{
+    /* XXX: handle more errors */
+    if (ret == -ENOMEDIUM) {
+        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                            ASC_MEDIUM_NOT_PRESENT);
+    } else {
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_LOGICAL_BLOCK_OOR);
+    }
+}
+
+/* The whole ATAPI transfer logic is handled in this function */
+void ide_atapi_cmd_reply_end(IDEState *s)
+{
+    int byte_count_limit, size, ret;
+#ifdef DEBUG_IDE_ATAPI
+    printf("reply: tx_size=%d elem_tx_size=%d index=%d\n",
+           s->packet_transfer_size,
+           s->elementary_transfer_size,
+           s->io_buffer_index);
+#endif
+    if (s->packet_transfer_size <= 0) {
+        /* end of transfer */
+        ide_transfer_stop(s);
+        s->status = READY_STAT | SEEK_STAT;
+        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+        ide_set_irq(s->bus);
+#ifdef DEBUG_IDE_ATAPI
+        printf("status=0x%x\n", s->status);
+#endif
+    } else {
+        /* see if a new sector must be read */
+        if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
+            ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size);
+            if (ret < 0) {
+                ide_transfer_stop(s);
+                ide_atapi_io_error(s, ret);
+                return;
+            }
+            s->lba++;
+            s->io_buffer_index = 0;
+        }
+        if (s->elementary_transfer_size > 0) {
+            /* there are some data left to transmit in this elementary
+               transfer */
+            size = s->cd_sector_size - s->io_buffer_index;
+            if (size > s->elementary_transfer_size)
+                size = s->elementary_transfer_size;
+            s->packet_transfer_size -= size;
+            s->elementary_transfer_size -= size;
+            s->io_buffer_index += size;
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
+                               size, ide_atapi_cmd_reply_end);
+        } else {
+            /* a new transfer is needed */
+            s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
+            byte_count_limit = s->lcyl | (s->hcyl << 8);
+#ifdef DEBUG_IDE_ATAPI
+            printf("byte_count_limit=%d\n", byte_count_limit);
+#endif
+            if (byte_count_limit == 0xffff)
+                byte_count_limit--;
+            size = s->packet_transfer_size;
+            if (size > byte_count_limit) {
+                /* byte count limit must be even if this case */
+                if (byte_count_limit & 1)
+                    byte_count_limit--;
+                size = byte_count_limit;
+            }
+            s->lcyl = size;
+            s->hcyl = size >> 8;
+            s->elementary_transfer_size = size;
+            /* we cannot transmit more than one sector at a time */
+            if (s->lba != -1) {
+                if (size > (s->cd_sector_size - s->io_buffer_index))
+                    size = (s->cd_sector_size - s->io_buffer_index);
+            }
+            s->packet_transfer_size -= size;
+            s->elementary_transfer_size -= size;
+            s->io_buffer_index += size;
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
+                               size, ide_atapi_cmd_reply_end);
+            ide_set_irq(s->bus);
+#ifdef DEBUG_IDE_ATAPI
+            printf("status=0x%x\n", s->status);
+#endif
+        }
+    }
+}
+
+/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
+static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
+{
+    if (size > max_size)
+        size = max_size;
+    s->lba = -1; /* no sector read */
+    s->packet_transfer_size = size;
+    s->io_buffer_size = size;    /* dma: send the reply data as one chunk */
+    s->elementary_transfer_size = 0;
+    s->io_buffer_index = 0;
+
+    if (s->atapi_dma) {
+        s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
+        s->bus->dma->ops->start_dma(s->bus->dma, s,
+                                   ide_atapi_cmd_read_dma_cb);
+    } else {
+        s->status = READY_STAT | SEEK_STAT;
+        ide_atapi_cmd_reply_end(s);
+    }
+}
+
+/* start a CD-CDROM read command */
+static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
+                                   int sector_size)
+{
+    s->lba = lba;
+    s->packet_transfer_size = nb_sectors * sector_size;
+    s->elementary_transfer_size = 0;
+    s->io_buffer_index = sector_size;
+    s->cd_sector_size = sector_size;
+
+    s->status = READY_STAT | SEEK_STAT;
+    ide_atapi_cmd_reply_end(s);
+}
+
+static void ide_atapi_cmd_check_status(IDEState *s)
+{
+#ifdef DEBUG_IDE_ATAPI
+    printf("atapi_cmd_check_status\n");
+#endif
+    s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4);
+    s->status = ERR_STAT;
+    s->nsector = 0;
+    ide_set_irq(s->bus);
+}
+/* ATAPI DMA support */
+
+/* XXX: handle read errors */
+static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
+{
+    IDEState *s = opaque;
+    int data_offset, n;
+
+    if (ret < 0) {
+        ide_atapi_io_error(s, ret);
+        goto eot;
+    }
+
+    if (s->io_buffer_size > 0) {
+        /*
+         * For a cdrom read sector command (s->lba != -1),
+         * adjust the lba for the next s->io_buffer_size chunk
+         * and dma the current chunk.
+         * For a command != read (s->lba == -1), just transfer
+         * the reply data.
+         */
+        if (s->lba != -1) {
+            if (s->cd_sector_size == 2352) {
+                n = 1;
+                cd_data_to_raw(s->io_buffer, s->lba);
+            } else {
+                n = s->io_buffer_size >> 11;
+            }
+            s->lba += n;
+        }
+        s->packet_transfer_size -= s->io_buffer_size;
+        if (s->bus->dma->ops->rw_buf(s->bus->dma, 1) == 0)
+            goto eot;
+    }
+
+    if (s->packet_transfer_size <= 0) {
+        s->status = READY_STAT | SEEK_STAT;
+        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+        ide_set_irq(s->bus);
+    eot:
+        s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
+        ide_set_inactive(s);
+        return;
+    }
+
+    s->io_buffer_index = 0;
+    if (s->cd_sector_size == 2352) {
+        n = 1;
+        s->io_buffer_size = s->cd_sector_size;
+        data_offset = 16;
+    } else {
+        n = s->packet_transfer_size >> 11;
+        if (n > (IDE_DMA_BUF_SECTORS / 4))
+            n = (IDE_DMA_BUF_SECTORS / 4);
+        s->io_buffer_size = n * 2048;
+        data_offset = 0;
+    }
+#ifdef DEBUG_AIO
+    printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
+#endif
+    s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset);
+    s->bus->dma->iov.iov_len = n * 4 * 512;
+    qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1);
+    s->bus->dma->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2,
+                                       &s->bus->dma->qiov, n * 4,
+                                       ide_atapi_cmd_read_dma_cb, s);
+    if (!s->bus->dma->aiocb) {
+        /* Note: media not present is the most likely case */
+        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                            ASC_MEDIUM_NOT_PRESENT);
+        goto eot;
+    }
+}
+
+/* start a CD-CDROM read command with DMA */
+/* XXX: test if DMA is available */
+static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
+                                   int sector_size)
+{
+    s->lba = lba;
+    s->packet_transfer_size = nb_sectors * sector_size;
+    s->io_buffer_index = 0;
+    s->io_buffer_size = 0;
+    s->cd_sector_size = sector_size;
+
+    /* XXX: check if BUSY_STAT should be set */
+    s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
+    s->bus->dma->ops->start_dma(s->bus->dma, s,
+                               ide_atapi_cmd_read_dma_cb);
+}
+
+static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
+                               int sector_size)
+{
+#ifdef DEBUG_IDE_ATAPI
+    printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio",
+        lba, nb_sectors);
+#endif
+    if (s->atapi_dma) {
+        ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size);
+    } else {
+        ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size);
+    }
+}
+
+static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
+                                            uint16_t profile)
+{
+    uint8_t *buf_profile = buf + 12; /* start of profiles */
+
+    buf_profile += ((*index) * 4); /* start of indexed profile */
+    cpu_to_ube16 (buf_profile, profile);
+    buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7]));
+
+    /* each profile adds 4 bytes to the response */
+    (*index)++;
+    buf[11] += 4; /* Additional Length */
+
+    return 4;
+}
+
+static int ide_dvd_read_structure(IDEState *s, int format,
+                                  const uint8_t *packet, uint8_t *buf)
+{
+    switch (format) {
+        case 0x0: /* Physical format information */
+            {
+                int layer = packet[6];
+                uint64_t total_sectors;
+
+                if (layer != 0)
+                    return -ASC_INV_FIELD_IN_CMD_PACKET;
+
+                total_sectors = s->nb_sectors >> 2;
+                if (total_sectors == 0) {
+                    return -ASC_MEDIUM_NOT_PRESENT;
+                }
+
+                buf[4] = 1;   /* DVD-ROM, part version 1 */
+                buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
+                buf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
+                buf[7] = 0;   /* default densities */
+
+                /* FIXME: 0x30000 per spec? */
+                cpu_to_ube32(buf + 8, 0); /* start sector */
+                cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */
+                cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */
+
+                /* Size of buffer, not including 2 byte size field */
+                cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+
+                /* 2k data + 4 byte header */
+                return (2048 + 4);
+            }
+
+        case 0x01: /* DVD copyright information */
+            buf[4] = 0; /* no copyright data */
+            buf[5] = 0; /* no region restrictions */
+
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 4 + 2);
+
+            /* 4 byte header + 4 byte data */
+            return (4 + 4);
+
+        case 0x03: /* BCA information - invalid field for no BCA info */
+            return -ASC_INV_FIELD_IN_CMD_PACKET;
+
+        case 0x04: /* DVD disc manufacturing information */
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+
+            /* 2k data + 4 byte header */
+            return (2048 + 4);
+
+        case 0xff:
+            /*
+             * This lists all the command capabilities above.  Add new ones
+             * in order and update the length and buffer return values.
+             */
+
+            buf[4] = 0x00; /* Physical format */
+            buf[5] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4);
+
+            buf[8] = 0x01; /* Copyright info */
+            buf[9] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4);
+
+            buf[12] = 0x03; /* BCA info */
+            buf[13] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4);
+
+            buf[16] = 0x04; /* Manufacturing info */
+            buf[17] = 0x40; /* Not writable, is readable */
+            cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4);
+
+            /* Size of buffer, not including 2 byte size field */
+            cpu_to_be16wu((uint16_t *)buf, 16 + 2);
+
+            /* data written + 4 byte header */
+            return (16 + 4);
+
+        default: /* TODO: formats beyond DVD-ROM requires */
+            return -ASC_INV_FIELD_IN_CMD_PACKET;
+    }
+}
+
+static unsigned int event_status_media(IDEState *s,
+                                       uint8_t *buf)
+{
+    enum media_event_code {
+        MEC_NO_CHANGE = 0,       /* Status unchanged */
+        MEC_EJECT_REQUESTED,     /* received a request from user to eject */
+        MEC_NEW_MEDIA,           /* new media inserted and ready for access */
+        MEC_MEDIA_REMOVAL,       /* only for media changers */
+        MEC_MEDIA_CHANGED,       /* only for media changers */
+        MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */
+        MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */
+    };
+    enum media_status {
+        MS_TRAY_OPEN = 1,
+        MS_MEDIA_PRESENT = 2,
+    };
+    uint8_t event_code, media_status;
+
+    media_status = 0;
+    if (s->bs->tray_open) {
+        media_status = MS_TRAY_OPEN;
+    } else if (bdrv_is_inserted(s->bs)) {
+        media_status = MS_MEDIA_PRESENT;
+    }
+
+    /* Event notification descriptor */
+    event_code = MEC_NO_CHANGE;
+    if (media_status != MS_TRAY_OPEN && s->events.new_media) {
+        event_code = MEC_NEW_MEDIA;
+        s->events.new_media = false;
+    }
+
+    buf[4] = event_code;
+    buf[5] = media_status;
+
+    /* These fields are reserved, just clear them. */
+    buf[6] = 0;
+    buf[7] = 0;
+
+    return 8; /* We wrote to 4 extra bytes from the header */
+}
+
+static void cmd_get_event_status_notification(IDEState *s,
+                                              uint8_t *buf)
+{
+    const uint8_t *packet = buf;
+
+    struct {
+        uint8_t opcode;
+        uint8_t polled;        /* lsb bit is polled; others are reserved */
+        uint8_t reserved2[2];
+        uint8_t class;
+        uint8_t reserved3[2];
+        uint16_t len;
+        uint8_t control;
+    } __attribute__((packed)) *gesn_cdb;
+
+    struct {
+        uint16_t len;
+        uint8_t notification_class;
+        uint8_t supported_events;
+    } __attribute((packed)) *gesn_event_header;
+
+    enum notification_class_request_type {
+        NCR_RESERVED1 = 1 << 0,
+        NCR_OPERATIONAL_CHANGE = 1 << 1,
+        NCR_POWER_MANAGEMENT = 1 << 2,
+        NCR_EXTERNAL_REQUEST = 1 << 3,
+        NCR_MEDIA = 1 << 4,
+        NCR_MULTI_HOST = 1 << 5,
+        NCR_DEVICE_BUSY = 1 << 6,
+        NCR_RESERVED2 = 1 << 7,
+    };
+    enum event_notification_class_field {
+        ENC_NO_EVENTS = 0,
+        ENC_OPERATIONAL_CHANGE,
+        ENC_POWER_MANAGEMENT,
+        ENC_EXTERNAL_REQUEST,
+        ENC_MEDIA,
+        ENC_MULTIPLE_HOSTS,
+        ENC_DEVICE_BUSY,
+        ENC_RESERVED,
+    };
+    unsigned int max_len, used_len;
+
+    gesn_cdb = (void *)packet;
+    gesn_event_header = (void *)buf;
+
+    max_len = be16_to_cpu(gesn_cdb->len);
+
+    /* It is fine by the MMC spec to not support async mode operations */
+    if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */
+        /* Only polling is supported, asynchronous mode is not. */
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_INV_FIELD_IN_CMD_PACKET);
+        return;
+    }
+
+    /* polling mode operation */
+
+    /*
+     * These are the supported events.
+     *
+     * We currently only support requests of the 'media' type.
+     */
+    gesn_event_header->supported_events = NCR_MEDIA;
+
+    /*
+     * We use |= below to set the class field; other bits in this byte
+     * are reserved now but this is useful to do if we have to use the
+     * reserved fields later.
+     */
+    gesn_event_header->notification_class = 0;
+
+    /*
+     * Responses to requests are to be based on request priority.  The
+     * notification_class_request_type enum above specifies the
+     * priority: upper elements are higher prio than lower ones.
+     */
+    if (gesn_cdb->class & NCR_MEDIA) {
+        gesn_event_header->notification_class |= ENC_MEDIA;
+        used_len = event_status_media(s, buf);
+    } else {
+        gesn_event_header->notification_class = 0x80; /* No event available */
+        used_len = sizeof(*gesn_event_header);
+    }
+    gesn_event_header->len = cpu_to_be16(used_len
+                                         - sizeof(*gesn_event_header));
+    ide_atapi_cmd_reply(s, used_len, max_len);
+}
+
+static void cmd_request_sense(IDEState *s, uint8_t *buf)
+{
+    int max_len = buf[4];
+
+    memset(buf, 0, 18);
+    buf[0] = 0x70 | (1 << 7);
+    buf[2] = s->sense_key;
+    buf[7] = 10;
+    buf[12] = s->asc;
+
+    if (s->sense_key == SENSE_UNIT_ATTENTION) {
+        s->sense_key = SENSE_NONE;
+    }
+
+    ide_atapi_cmd_reply(s, 18, max_len);
+}
+
+static void cmd_inquiry(IDEState *s, uint8_t *buf)
+{
+    int max_len = buf[4];
+
+    buf[0] = 0x05; /* CD-ROM */
+    buf[1] = 0x80; /* removable */
+    buf[2] = 0x00; /* ISO */
+    buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
+    buf[4] = 31; /* additional length */
+    buf[5] = 0; /* reserved */
+    buf[6] = 0; /* reserved */
+    buf[7] = 0; /* reserved */
+    padstr8(buf + 8, 8, "QEMU");
+    padstr8(buf + 16, 16, "QEMU DVD-ROM");
+    padstr8(buf + 32, 4, s->version);
+    ide_atapi_cmd_reply(s, 36, max_len);
+}
+
+static void cmd_get_configuration(IDEState *s, uint8_t *buf)
+{
+    uint32_t len;
+    uint8_t index = 0;
+    int max_len;
+
+    /* only feature 0 is supported */
+    if (buf[2] != 0 || buf[3] != 0) {
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_INV_FIELD_IN_CMD_PACKET);
+        return;
+    }
+
+    /* XXX: could result in alignment problems in some architectures */
+    max_len = ube16_to_cpu(buf + 7);
+
+    /*
+     * XXX: avoid overflow for io_buffer if max_len is bigger than
+     *      the size of that buffer (dimensioned to max number of
+     *      sectors to transfer at once)
+     *
+     *      Only a problem if the feature/profiles grow.
+     */
+    if (max_len > 512) {
+        /* XXX: assume 1 sector */
+        max_len = 512;
+    }
+
+    memset(buf, 0, max_len);
+    /*
+     * the number of sectors from the media tells us which profile
+     * to use as current.  0 means there is no media
+     */
+    if (media_is_dvd(s)) {
+        cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
+    } else if (media_is_cd(s)) {
+        cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
+    }
+
+    buf[10] = 0x02 | 0x01; /* persistent and current */
+    len = 12; /* headers: 8 + 4 */
+    len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM);
+    len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM);
+    cpu_to_ube32(buf, len - 4); /* data length */
+
+    ide_atapi_cmd_reply(s, len, max_len);
+}
+
+static void cmd_mode_sense(IDEState *s, uint8_t *buf)
+{
+    int action, code;
+    int max_len;
+
+    if (buf[0] == GPCMD_MODE_SENSE_10) {
+        max_len = ube16_to_cpu(buf + 7);
+    } else {
+        max_len = buf[4];
+    }
+
+    action = buf[2] >> 6;
+    code = buf[2] & 0x3f;
+
+    switch(action) {
+    case 0: /* current values */
+        switch(code) {
+        case GPMODE_R_W_ERROR_PAGE: /* error recovery */
+            cpu_to_ube16(&buf[0], 16 + 6);
+            buf[2] = 0x70;
+            buf[3] = 0;
+            buf[4] = 0;
+            buf[5] = 0;
+            buf[6] = 0;
+            buf[7] = 0;
+
+            buf[8] = 0x01;
+            buf[9] = 0x06;
+            buf[10] = 0x00;
+            buf[11] = 0x05;
+            buf[12] = 0x00;
+            buf[13] = 0x00;
+            buf[14] = 0x00;
+            buf[15] = 0x00;
+            ide_atapi_cmd_reply(s, 16, max_len);
+            break;
+        case GPMODE_AUDIO_CTL_PAGE:
+            cpu_to_ube16(&buf[0], 24 + 6);
+            buf[2] = 0x70;
+            buf[3] = 0;
+            buf[4] = 0;
+            buf[5] = 0;
+            buf[6] = 0;
+            buf[7] = 0;
+
+            /* Fill with CDROM audio volume */
+            buf[17] = 0;
+            buf[19] = 0;
+            buf[21] = 0;
+            buf[23] = 0;
+
+            ide_atapi_cmd_reply(s, 24, max_len);
+            break;
+        case GPMODE_CAPABILITIES_PAGE:
+            cpu_to_ube16(&buf[0], 28 + 6);
+            buf[2] = 0x70;
+            buf[3] = 0;
+            buf[4] = 0;
+            buf[5] = 0;
+            buf[6] = 0;
+            buf[7] = 0;
+
+            buf[8] = 0x2a;
+            buf[9] = 0x12;
+            buf[10] = 0x00;
+            buf[11] = 0x00;
+
+            /* Claim PLAY_AUDIO capability (0x01) since some Linux
+               code checks for this to automount media. */
+            buf[12] = 0x71;
+            buf[13] = 3 << 5;
+            buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
+            if (bdrv_is_locked(s->bs))
+                buf[6] |= 1 << 1;
+            buf[15] = 0x00;
+            cpu_to_ube16(&buf[16], 706);
+            buf[18] = 0;
+            buf[19] = 2;
+            cpu_to_ube16(&buf[20], 512);
+            cpu_to_ube16(&buf[22], 706);
+            buf[24] = 0;
+            buf[25] = 0;
+            buf[26] = 0;
+            buf[27] = 0;
+            ide_atapi_cmd_reply(s, 28, max_len);
+            break;
+        default:
+            goto error_cmd;
+        }
+        break;
+    case 1: /* changeable values */
+        goto error_cmd;
+    case 2: /* default values */
+        goto error_cmd;
+    default:
+    case 3: /* saved values */
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
+        break;
+    }
+    return;
+
+error_cmd:
+    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+}
+
+static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
+{
+    /* Not Ready Conditions are already handled in ide_atapi_cmd(), so if we
+     * come here, we know that it's ready. */
+    ide_atapi_cmd_ok(s);
+}
+
+static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
+{
+    bdrv_set_locked(s->bs, buf[4] & 1);
+    ide_atapi_cmd_ok(s);
+}
+
+static void cmd_read(IDEState *s, uint8_t* buf)
+{
+    int nb_sectors, lba;
+
+    if (buf[0] == GPCMD_READ_10) {
+        nb_sectors = ube16_to_cpu(buf + 7);
+    } else {
+        nb_sectors = ube32_to_cpu(buf + 6);
+    }
+
+    lba = ube32_to_cpu(buf + 2);
+    if (nb_sectors == 0) {
+        ide_atapi_cmd_ok(s);
+        return;
+    }
+
+    ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
+}
+
+static void cmd_read_cd(IDEState *s, uint8_t* buf)
+{
+    int nb_sectors, lba, transfer_request;
+
+    nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8];
+    lba = ube32_to_cpu(buf + 2);
+
+    if (nb_sectors == 0) {
+        ide_atapi_cmd_ok(s);
+        return;
+    }
+
+    transfer_request = buf[9];
+    switch(transfer_request & 0xf8) {
+    case 0x00:
+        /* nothing */
+        ide_atapi_cmd_ok(s);
+        break;
+    case 0x10:
+        /* normal read */
+        ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
+        break;
+    case 0xf8:
+        /* read all data */
+        ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
+        break;
+    default:
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_INV_FIELD_IN_CMD_PACKET);
+        break;
+    }
+}
+
+static void cmd_seek(IDEState *s, uint8_t* buf)
+{
+    unsigned int lba;
+    uint64_t total_sectors = s->nb_sectors >> 2;
+
+    lba = ube32_to_cpu(buf + 2);
+    if (lba >= total_sectors) {
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
+        return;
+    }
+
+    ide_atapi_cmd_ok(s);
+}
+
+static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
+{
+    int start, eject, sense, err = 0;
+    start = buf[4] & 1;
+    eject = (buf[4] >> 1) & 1;
+
+    if (eject) {
+        err = bdrv_eject(s->bs, !start);
+    }
+
+    switch (err) {
+    case 0:
+        ide_atapi_cmd_ok(s);
+        break;
+    case -EBUSY:
+        sense = SENSE_NOT_READY;
+        if (bdrv_is_inserted(s->bs)) {
+            sense = SENSE_ILLEGAL_REQUEST;
+        }
+        ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
+        break;
+    default:
+        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+        break;
+    }
+}
+
+static void cmd_mechanism_status(IDEState *s, uint8_t* buf)
+{
+    int max_len = ube16_to_cpu(buf + 8);
+
+    cpu_to_ube16(buf, 0);
+    /* no current LBA */
+    buf[2] = 0;
+    buf[3] = 0;
+    buf[4] = 0;
+    buf[5] = 1;
+    cpu_to_ube16(buf + 6, 0);
+    ide_atapi_cmd_reply(s, 8, max_len);
+}
+
+static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf)
+{
+    int format, msf, start_track, len;
+    int max_len;
+    uint64_t total_sectors = s->nb_sectors >> 2;
+
+    max_len = ube16_to_cpu(buf + 7);
+    format = buf[9] >> 6;
+    msf = (buf[1] >> 1) & 1;
+    start_track = buf[6];
+
+    switch(format) {
+    case 0:
+        len = cdrom_read_toc(total_sectors, buf, msf, start_track);
+        if (len < 0)
+            goto error_cmd;
+        ide_atapi_cmd_reply(s, len, max_len);
+        break;
+    case 1:
+        /* multi session : only a single session defined */
+        memset(buf, 0, 12);
+        buf[1] = 0x0a;
+        buf[2] = 0x01;
+        buf[3] = 0x01;
+        ide_atapi_cmd_reply(s, 12, max_len);
+        break;
+    case 2:
+        len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track);
+        if (len < 0)
+            goto error_cmd;
+        ide_atapi_cmd_reply(s, len, max_len);
+        break;
+    default:
+    error_cmd:
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_INV_FIELD_IN_CMD_PACKET);
+    }
+}
+
+static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf)
+{
+    uint64_t total_sectors = s->nb_sectors >> 2;
+
+    /* NOTE: it is really the number of sectors minus 1 */
+    cpu_to_ube32(buf, total_sectors - 1);
+    cpu_to_ube32(buf + 4, 2048);
+    ide_atapi_cmd_reply(s, 8, 8);
+}
+
+static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
+{
+    int max_len;
+    int media = buf[1];
+    int format = buf[7];
+    int ret;
+
+    max_len = ube16_to_cpu(buf + 8);
+
+    if (format < 0xff) {
+        if (media_is_cd(s)) {
+            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                ASC_INCOMPATIBLE_FORMAT);
+            return;
+        } else if (!media_present(s)) {
+            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                ASC_INV_FIELD_IN_CMD_PACKET);
+            return;
+        }
+    }
+
+    memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
+           IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
+
+    switch (format) {
+        case 0x00 ... 0x7f:
+        case 0xff:
+            if (media == 0) {
+                ret = ide_dvd_read_structure(s, format, buf, buf);
+
+                if (ret < 0) {
+                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
+                } else {
+                    ide_atapi_cmd_reply(s, ret, max_len);
+                }
+
+                break;
+            }
+            /* TODO: BD support, fall through for now */
+
+        /* Generic disk structures */
+        case 0x80: /* TODO: AACS volume identifier */
+        case 0x81: /* TODO: AACS media serial number */
+        case 0x82: /* TODO: AACS media identifier */
+        case 0x83: /* TODO: AACS media key block */
+        case 0x90: /* TODO: List of recognized format layers */
+        case 0xc0: /* TODO: Write protection status */
+        default:
+            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                ASC_INV_FIELD_IN_CMD_PACKET);
+            break;
+    }
+}
+
+static void cmd_set_speed(IDEState *s, uint8_t* buf)
+{
+    ide_atapi_cmd_ok(s);
+}
+
+enum {
+    /*
+     * Only commands flagged as ALLOW_UA are allowed to run under a
+     * unit attention condition. (See MMC-5, section 4.1.6.1)
+     */
+    ALLOW_UA = 0x01,
+
+    /*
+     * Commands flagged with CHECK_READY can only execute if a medium is present.
+     * Otherwise they report the Not Ready Condition. (See MMC-5, section
+     * 4.1.8)
+     */
+    CHECK_READY = 0x02,
+};
+
+static const struct {
+    void (*handler)(IDEState *s, uint8_t *buf);
+    int flags;
+} atapi_cmd_table[0x100] = {
+    [ 0x00 ] = { cmd_test_unit_ready,               CHECK_READY },
+    [ 0x03 ] = { cmd_request_sense,                 ALLOW_UA },
+    [ 0x12 ] = { cmd_inquiry,                       ALLOW_UA },
+    [ 0x1a ] = { cmd_mode_sense, /* (6) */          0 },
+    [ 0x1b ] = { cmd_start_stop_unit,               0 },
+    [ 0x1e ] = { cmd_prevent_allow_medium_removal,  0 },
+    [ 0x25 ] = { cmd_read_cdvd_capacity,            CHECK_READY },
+    [ 0x28 ] = { cmd_read, /* (10) */               0 },
+    [ 0x2b ] = { cmd_seek,                          CHECK_READY },
+    [ 0x43 ] = { cmd_read_toc_pma_atip,             CHECK_READY },
+    [ 0x46 ] = { cmd_get_configuration,             ALLOW_UA },
+    [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
+    [ 0x5a ] = { cmd_mode_sense, /* (10) */         0 },
+    [ 0xa8 ] = { cmd_read, /* (12) */               0 },
+    [ 0xad ] = { cmd_read_dvd_structure,            0 },
+    [ 0xbb ] = { cmd_set_speed,                     0 },
+    [ 0xbd ] = { cmd_mechanism_status,              0 },
+    [ 0xbe ] = { cmd_read_cd,                       0 },
+};
+
+void ide_atapi_cmd(IDEState *s)
+{
+    uint8_t *buf;
+
+    buf = s->io_buffer;
+#ifdef DEBUG_IDE_ATAPI
+    {
+        int i;
+        printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8));
+        for(i = 0; i < ATAPI_PACKET_SIZE; i++) {
+            printf(" %02x", buf[i]);
+        }
+        printf("\n");
+    }
+#endif
+    /*
+     * If there's a UNIT_ATTENTION condition pending, only command flagged with
+     * ALLOW_UA are allowed to complete. with other commands getting a CHECK
+     * condition response unless a higher priority status, defined by the drive
+     * here, is pending.
+     */
+    if (s->sense_key == SENSE_UNIT_ATTENTION &&
+        !(atapi_cmd_table[s->io_buffer[0]].flags & ALLOW_UA)) {
+        ide_atapi_cmd_check_status(s);
+        return;
+    }
+    /*
+     * When a CD gets changed, we have to report an ejected state and
+     * then a loaded state to guests so that they detect tray
+     * open/close and media change events.  Guests that do not use
+     * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
+     * states rely on this behavior.
+     */
+    if (bdrv_is_inserted(s->bs) && s->cdrom_changed) {
+        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+
+        s->cdrom_changed = 0;
+        s->sense_key = SENSE_UNIT_ATTENTION;
+        s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
+        return;
+    }
+
+    /* Report a Not Ready condition if appropriate for the command */
+    if ((atapi_cmd_table[s->io_buffer[0]].flags & CHECK_READY) &&
+        (!media_present(s) || !bdrv_is_inserted(s->bs)))
+    {
+        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+        return;
+    }
+
+    /* Execute the command */
+    if (atapi_cmd_table[s->io_buffer[0]].handler) {
+        atapi_cmd_table[s->io_buffer[0]].handler(s, buf);
+        return;
+    }
+
+    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE);
+}
index 007a4ee0c9cad3b6d728126b66f8dbf5b9dc6c95..90f553b69b47bae6bc956b97d3a2f24c3c674584 100644 (file)
@@ -25,7 +25,6 @@
 #include <hw/hw.h>
 #include <hw/pc.h>
 #include <hw/pci.h>
-#include <hw/scsi.h>
 #include "qemu-error.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
@@ -56,23 +55,6 @@ static const int smart_attributes[][12] = {
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-/* XXX: DVDs that could fit on a CD will be reported as a CD */
-static inline int media_present(IDEState *s)
-{
-    return (s->nb_sectors > 0);
-}
-
-static inline int media_is_dvd(IDEState *s)
-{
-    return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS);
-}
-
-static inline int media_is_cd(IDEState *s)
-{
-    return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
-}
-
-static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
 static int ide_handle_rw_error(IDEState *s, int error, int op);
 
 static void padstr(char *str, const char *src, int len)
@@ -87,17 +69,6 @@ static void padstr(char *str, const char *src, int len)
     }
 }
 
-static void padstr8(uint8_t *buf, int buf_size, const char *src)
-{
-    int i;
-    for(i = 0; i < buf_size; i++) {
-        if (*src)
-            buf[i] = *src++;
-        else
-            buf[i] = ' ';
-    }
-}
-
 static void put_le16(uint16_t *p, unsigned int v)
 {
     *p = cpu_to_le16(v);
@@ -335,8 +306,8 @@ static inline void ide_abort_command(IDEState *s)
 }
 
 /* prepare data transfer and tell what to do after */
-static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
-                               EndTransferFunc *end_transfer_func)
+void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
+                        EndTransferFunc *end_transfer_func)
 {
     s->end_transfer_func = end_transfer_func;
     s->data_ptr = buf;
@@ -347,7 +318,7 @@ static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
     s->bus->dma->ops->start_transfer(s->bus->dma);
 }
 
-static void ide_transfer_stop(IDEState *s)
+void ide_transfer_stop(IDEState *s)
 {
     s->end_transfer_func = ide_transfer_stop;
     s->data_ptr = s->io_buffer;
@@ -447,7 +418,7 @@ static void dma_buf_commit(IDEState *s, int is_write)
     qemu_sglist_destroy(&s->sg);
 }
 
-static void ide_set_inactive(IDEState *s)
+void ide_set_inactive(IDEState *s)
 {
     s->bus->dma->aiocb = NULL;
     s->bus->dma->ops->set_inactive(s->bus->dma);
@@ -617,38 +588,6 @@ void ide_sector_write(IDEState *s)
     }
 }
 
-void ide_atapi_cmd_ok(IDEState *s)
-{
-    s->error = 0;
-    s->status = READY_STAT | SEEK_STAT;
-    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
-    ide_set_irq(s->bus);
-}
-
-void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc)
-{
-#ifdef DEBUG_IDE_ATAPI
-    printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc);
-#endif
-    s->error = sense_key << 4;
-    s->status = READY_STAT | ERR_STAT;
-    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
-    s->sense_key = sense_key;
-    s->asc = asc;
-    ide_set_irq(s->bus);
-}
-
-static void ide_atapi_cmd_check_status(IDEState *s)
-{
-#ifdef DEBUG_IDE_ATAPI
-    printf("atapi_cmd_check_status\n");
-#endif
-    s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4);
-    s->status = ERR_STAT;
-    s->nsector = 0;
-    ide_set_irq(s->bus);
-}
-
 static void ide_flush_cb(void *opaque, int ret)
 {
     IDEState *s = opaque;
@@ -679,870 +618,6 @@ void ide_flush_cache(IDEState *s)
     }
 }
 
-static inline void cpu_to_ube16(uint8_t *buf, int val)
-{
-    buf[0] = val >> 8;
-    buf[1] = val & 0xff;
-}
-
-static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
-{
-    buf[0] = val >> 24;
-    buf[1] = val >> 16;
-    buf[2] = val >> 8;
-    buf[3] = val & 0xff;
-}
-
-static inline int ube16_to_cpu(const uint8_t *buf)
-{
-    return (buf[0] << 8) | buf[1];
-}
-
-static inline int ube32_to_cpu(const uint8_t *buf)
-{
-    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-}
-
-static void lba_to_msf(uint8_t *buf, int lba)
-{
-    lba += 150;
-    buf[0] = (lba / 75) / 60;
-    buf[1] = (lba / 75) % 60;
-    buf[2] = lba % 75;
-}
-
-static void cd_data_to_raw(uint8_t *buf, int lba)
-{
-    /* sync bytes */
-    buf[0] = 0x00;
-    memset(buf + 1, 0xff, 10);
-    buf[11] = 0x00;
-    buf += 12;
-    /* MSF */
-    lba_to_msf(buf, lba);
-    buf[3] = 0x01; /* mode 1 data */
-    buf += 4;
-    /* data */
-    buf += 2048;
-    /* XXX: ECC not computed */
-    memset(buf, 0, 288);
-}
-
-static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
-                           int sector_size)
-{
-    int ret;
-
-    switch(sector_size) {
-    case 2048:
-        ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4);
-        break;
-    case 2352:
-        ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4);
-        if (ret < 0)
-            return ret;
-        cd_data_to_raw(buf, lba);
-        break;
-    default:
-        ret = -EIO;
-        break;
-    }
-    return ret;
-}
-
-void ide_atapi_io_error(IDEState *s, int ret)
-{
-    /* XXX: handle more errors */
-    if (ret == -ENOMEDIUM) {
-        ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                            ASC_MEDIUM_NOT_PRESENT);
-    } else {
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                            ASC_LOGICAL_BLOCK_OOR);
-    }
-}
-
-/* The whole ATAPI transfer logic is handled in this function */
-static void ide_atapi_cmd_reply_end(IDEState *s)
-{
-    int byte_count_limit, size, ret;
-#ifdef DEBUG_IDE_ATAPI
-    printf("reply: tx_size=%d elem_tx_size=%d index=%d\n",
-           s->packet_transfer_size,
-           s->elementary_transfer_size,
-           s->io_buffer_index);
-#endif
-    if (s->packet_transfer_size <= 0) {
-        /* end of transfer */
-        ide_transfer_stop(s);
-        s->status = READY_STAT | SEEK_STAT;
-        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
-        ide_set_irq(s->bus);
-#ifdef DEBUG_IDE_ATAPI
-        printf("status=0x%x\n", s->status);
-#endif
-    } else {
-        /* see if a new sector must be read */
-        if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
-            ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size);
-            if (ret < 0) {
-                ide_transfer_stop(s);
-                ide_atapi_io_error(s, ret);
-                return;
-            }
-            s->lba++;
-            s->io_buffer_index = 0;
-        }
-        if (s->elementary_transfer_size > 0) {
-            /* there are some data left to transmit in this elementary
-               transfer */
-            size = s->cd_sector_size - s->io_buffer_index;
-            if (size > s->elementary_transfer_size)
-                size = s->elementary_transfer_size;
-            s->packet_transfer_size -= size;
-            s->elementary_transfer_size -= size;
-            s->io_buffer_index += size;
-            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
-                               size, ide_atapi_cmd_reply_end);
-        } else {
-            /* a new transfer is needed */
-            s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
-            byte_count_limit = s->lcyl | (s->hcyl << 8);
-#ifdef DEBUG_IDE_ATAPI
-            printf("byte_count_limit=%d\n", byte_count_limit);
-#endif
-            if (byte_count_limit == 0xffff)
-                byte_count_limit--;
-            size = s->packet_transfer_size;
-            if (size > byte_count_limit) {
-                /* byte count limit must be even if this case */
-                if (byte_count_limit & 1)
-                    byte_count_limit--;
-                size = byte_count_limit;
-            }
-            s->lcyl = size;
-            s->hcyl = size >> 8;
-            s->elementary_transfer_size = size;
-            /* we cannot transmit more than one sector at a time */
-            if (s->lba != -1) {
-                if (size > (s->cd_sector_size - s->io_buffer_index))
-                    size = (s->cd_sector_size - s->io_buffer_index);
-            }
-            s->packet_transfer_size -= size;
-            s->elementary_transfer_size -= size;
-            s->io_buffer_index += size;
-            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
-                               size, ide_atapi_cmd_reply_end);
-            ide_set_irq(s->bus);
-#ifdef DEBUG_IDE_ATAPI
-            printf("status=0x%x\n", s->status);
-#endif
-        }
-    }
-}
-
-/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
-static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
-{
-    if (size > max_size)
-        size = max_size;
-    s->lba = -1; /* no sector read */
-    s->packet_transfer_size = size;
-    s->io_buffer_size = size;    /* dma: send the reply data as one chunk */
-    s->elementary_transfer_size = 0;
-    s->io_buffer_index = 0;
-
-    if (s->atapi_dma) {
-       s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
-        s->bus->dma->ops->start_dma(s->bus->dma, s,
-                                   ide_atapi_cmd_read_dma_cb);
-    } else {
-       s->status = READY_STAT | SEEK_STAT;
-       ide_atapi_cmd_reply_end(s);
-    }
-}
-
-/* start a CD-CDROM read command */
-static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
-                                   int sector_size)
-{
-    s->lba = lba;
-    s->packet_transfer_size = nb_sectors * sector_size;
-    s->elementary_transfer_size = 0;
-    s->io_buffer_index = sector_size;
-    s->cd_sector_size = sector_size;
-
-    s->status = READY_STAT | SEEK_STAT;
-    ide_atapi_cmd_reply_end(s);
-}
-
-/* ATAPI DMA support */
-
-/* XXX: handle read errors */
-static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
-{
-    IDEState *s = opaque;
-    int data_offset, n;
-
-    if (ret < 0) {
-        ide_atapi_io_error(s, ret);
-        goto eot;
-    }
-
-    if (s->io_buffer_size > 0) {
-       /*
-        * For a cdrom read sector command (s->lba != -1),
-        * adjust the lba for the next s->io_buffer_size chunk
-        * and dma the current chunk.
-        * For a command != read (s->lba == -1), just transfer
-        * the reply data.
-        */
-       if (s->lba != -1) {
-           if (s->cd_sector_size == 2352) {
-               n = 1;
-               cd_data_to_raw(s->io_buffer, s->lba);
-           } else {
-               n = s->io_buffer_size >> 11;
-           }
-           s->lba += n;
-       }
-        s->packet_transfer_size -= s->io_buffer_size;
-        if (s->bus->dma->ops->rw_buf(s->bus->dma, 1) == 0)
-            goto eot;
-    }
-
-    if (s->packet_transfer_size <= 0) {
-        s->status = READY_STAT | SEEK_STAT;
-        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
-        ide_set_irq(s->bus);
-    eot:
-        s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
-        ide_set_inactive(s);
-        return;
-    }
-
-    s->io_buffer_index = 0;
-    if (s->cd_sector_size == 2352) {
-        n = 1;
-        s->io_buffer_size = s->cd_sector_size;
-        data_offset = 16;
-    } else {
-        n = s->packet_transfer_size >> 11;
-        if (n > (IDE_DMA_BUF_SECTORS / 4))
-            n = (IDE_DMA_BUF_SECTORS / 4);
-        s->io_buffer_size = n * 2048;
-        data_offset = 0;
-    }
-#ifdef DEBUG_AIO
-    printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
-#endif
-    s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset);
-    s->bus->dma->iov.iov_len = n * 4 * 512;
-    qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1);
-    s->bus->dma->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2,
-                                       &s->bus->dma->qiov, n * 4,
-                                       ide_atapi_cmd_read_dma_cb, s);
-    if (!s->bus->dma->aiocb) {
-        /* Note: media not present is the most likely case */
-        ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                            ASC_MEDIUM_NOT_PRESENT);
-        goto eot;
-    }
-}
-
-/* start a CD-CDROM read command with DMA */
-/* XXX: test if DMA is available */
-static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
-                                   int sector_size)
-{
-    s->lba = lba;
-    s->packet_transfer_size = nb_sectors * sector_size;
-    s->io_buffer_index = 0;
-    s->io_buffer_size = 0;
-    s->cd_sector_size = sector_size;
-
-    /* XXX: check if BUSY_STAT should be set */
-    s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
-    s->bus->dma->ops->start_dma(s->bus->dma, s,
-                               ide_atapi_cmd_read_dma_cb);
-}
-
-static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
-                               int sector_size)
-{
-#ifdef DEBUG_IDE_ATAPI
-    printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio",
-       lba, nb_sectors);
-#endif
-    if (s->atapi_dma) {
-        ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size);
-    } else {
-        ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size);
-    }
-}
-
-static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
-                                            uint16_t profile)
-{
-    uint8_t *buf_profile = buf + 12; /* start of profiles */
-
-    buf_profile += ((*index) * 4); /* start of indexed profile */
-    cpu_to_ube16 (buf_profile, profile);
-    buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7]));
-
-    /* each profile adds 4 bytes to the response */
-    (*index)++;
-    buf[11] += 4; /* Additional Length */
-
-    return 4;
-}
-
-static int ide_dvd_read_structure(IDEState *s, int format,
-                                  const uint8_t *packet, uint8_t *buf)
-{
-    switch (format) {
-        case 0x0: /* Physical format information */
-            {
-                int layer = packet[6];
-                uint64_t total_sectors;
-
-                if (layer != 0)
-                    return -ASC_INV_FIELD_IN_CMD_PACKET;
-
-                bdrv_get_geometry(s->bs, &total_sectors);
-                total_sectors >>= 2;
-                if (total_sectors == 0)
-                    return -ASC_MEDIUM_NOT_PRESENT;
-
-                buf[4] = 1;   /* DVD-ROM, part version 1 */
-                buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
-                buf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
-                buf[7] = 0;   /* default densities */
-
-                /* FIXME: 0x30000 per spec? */
-                cpu_to_ube32(buf + 8, 0); /* start sector */
-                cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */
-                cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */
-
-                /* Size of buffer, not including 2 byte size field */
-                cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
-
-                /* 2k data + 4 byte header */
-                return (2048 + 4);
-            }
-
-        case 0x01: /* DVD copyright information */
-            buf[4] = 0; /* no copyright data */
-            buf[5] = 0; /* no region restrictions */
-
-            /* Size of buffer, not including 2 byte size field */
-            cpu_to_be16wu((uint16_t *)buf, 4 + 2);
-
-            /* 4 byte header + 4 byte data */
-            return (4 + 4);
-
-        case 0x03: /* BCA information - invalid field for no BCA info */
-            return -ASC_INV_FIELD_IN_CMD_PACKET;
-
-        case 0x04: /* DVD disc manufacturing information */
-            /* Size of buffer, not including 2 byte size field */
-            cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
-
-            /* 2k data + 4 byte header */
-            return (2048 + 4);
-
-        case 0xff:
-            /*
-             * This lists all the command capabilities above.  Add new ones
-             * in order and update the length and buffer return values.
-             */
-
-            buf[4] = 0x00; /* Physical format */
-            buf[5] = 0x40; /* Not writable, is readable */
-            cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4);
-
-            buf[8] = 0x01; /* Copyright info */
-            buf[9] = 0x40; /* Not writable, is readable */
-            cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4);
-
-            buf[12] = 0x03; /* BCA info */
-            buf[13] = 0x40; /* Not writable, is readable */
-            cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4);
-
-            buf[16] = 0x04; /* Manufacturing info */
-            buf[17] = 0x40; /* Not writable, is readable */
-            cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4);
-
-            /* Size of buffer, not including 2 byte size field */
-            cpu_to_be16wu((uint16_t *)buf, 16 + 2);
-
-            /* data written + 4 byte header */
-            return (16 + 4);
-
-        default: /* TODO: formats beyond DVD-ROM requires */
-            return -ASC_INV_FIELD_IN_CMD_PACKET;
-    }
-}
-
-static void ide_atapi_cmd(IDEState *s)
-{
-    const uint8_t *packet;
-    uint8_t *buf;
-    int max_len;
-
-    packet = s->io_buffer;
-    buf = s->io_buffer;
-#ifdef DEBUG_IDE_ATAPI
-    {
-        int i;
-        printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8));
-        for(i = 0; i < ATAPI_PACKET_SIZE; i++) {
-            printf(" %02x", packet[i]);
-        }
-        printf("\n");
-    }
-#endif
-    /* If there's a UNIT_ATTENTION condition pending, only
-       REQUEST_SENSE and INQUIRY commands are allowed to complete. */
-    if (s->sense_key == SENSE_UNIT_ATTENTION &&
-       s->io_buffer[0] != GPCMD_REQUEST_SENSE &&
-       s->io_buffer[0] != GPCMD_INQUIRY) {
-       ide_atapi_cmd_check_status(s);
-       return;
-    }
-    switch(s->io_buffer[0]) {
-    case GPCMD_TEST_UNIT_READY:
-        if (bdrv_is_inserted(s->bs) && !s->cdrom_changed) {
-            ide_atapi_cmd_ok(s);
-        } else {
-            s->cdrom_changed = 0;
-            ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                                ASC_MEDIUM_NOT_PRESENT);
-        }
-        break;
-    case GPCMD_MODE_SENSE_6:
-    case GPCMD_MODE_SENSE_10:
-        {
-            int action, code;
-            if (packet[0] == GPCMD_MODE_SENSE_10)
-                max_len = ube16_to_cpu(packet + 7);
-            else
-                max_len = packet[4];
-            action = packet[2] >> 6;
-            code = packet[2] & 0x3f;
-            switch(action) {
-            case 0: /* current values */
-                switch(code) {
-                case GPMODE_R_W_ERROR_PAGE: /* error recovery */
-                    cpu_to_ube16(&buf[0], 16 + 6);
-                    buf[2] = 0x70;
-                    buf[3] = 0;
-                    buf[4] = 0;
-                    buf[5] = 0;
-                    buf[6] = 0;
-                    buf[7] = 0;
-
-                    buf[8] = 0x01;
-                    buf[9] = 0x06;
-                    buf[10] = 0x00;
-                    buf[11] = 0x05;
-                    buf[12] = 0x00;
-                    buf[13] = 0x00;
-                    buf[14] = 0x00;
-                    buf[15] = 0x00;
-                    ide_atapi_cmd_reply(s, 16, max_len);
-                    break;
-                case GPMODE_AUDIO_CTL_PAGE:
-                    cpu_to_ube16(&buf[0], 24 + 6);
-                    buf[2] = 0x70;
-                    buf[3] = 0;
-                    buf[4] = 0;
-                    buf[5] = 0;
-                    buf[6] = 0;
-                    buf[7] = 0;
-
-                    /* Fill with CDROM audio volume */
-                    buf[17] = 0;
-                    buf[19] = 0;
-                    buf[21] = 0;
-                    buf[23] = 0;
-
-                    ide_atapi_cmd_reply(s, 24, max_len);
-                    break;
-                case GPMODE_CAPABILITIES_PAGE:
-                    cpu_to_ube16(&buf[0], 28 + 6);
-                    buf[2] = 0x70;
-                    buf[3] = 0;
-                    buf[4] = 0;
-                    buf[5] = 0;
-                    buf[6] = 0;
-                    buf[7] = 0;
-
-                    buf[8] = 0x2a;
-                    buf[9] = 0x12;
-                    buf[10] = 0x00;
-                    buf[11] = 0x00;
-
-                    /* Claim PLAY_AUDIO capability (0x01) since some Linux
-                       code checks for this to automount media. */
-                    buf[12] = 0x71;
-                    buf[13] = 3 << 5;
-                    buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
-                    if (bdrv_is_locked(s->bs))
-                        buf[6] |= 1 << 1;
-                    buf[15] = 0x00;
-                    cpu_to_ube16(&buf[16], 706);
-                    buf[18] = 0;
-                    buf[19] = 2;
-                    cpu_to_ube16(&buf[20], 512);
-                    cpu_to_ube16(&buf[22], 706);
-                    buf[24] = 0;
-                    buf[25] = 0;
-                    buf[26] = 0;
-                    buf[27] = 0;
-                    ide_atapi_cmd_reply(s, 28, max_len);
-                    break;
-                default:
-                    goto error_cmd;
-                }
-                break;
-            case 1: /* changeable values */
-                goto error_cmd;
-            case 2: /* default values */
-                goto error_cmd;
-            default:
-            case 3: /* saved values */
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                    ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
-                break;
-            }
-        }
-        break;
-    case GPCMD_REQUEST_SENSE:
-        max_len = packet[4];
-        memset(buf, 0, 18);
-        buf[0] = 0x70 | (1 << 7);
-        buf[2] = s->sense_key;
-        buf[7] = 10;
-        buf[12] = s->asc;
-        if (s->sense_key == SENSE_UNIT_ATTENTION)
-            s->sense_key = SENSE_NONE;
-        ide_atapi_cmd_reply(s, 18, max_len);
-        break;
-    case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
-        if (bdrv_is_inserted(s->bs)) {
-            bdrv_set_locked(s->bs, packet[4] & 1);
-            ide_atapi_cmd_ok(s);
-        } else {
-            ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                                ASC_MEDIUM_NOT_PRESENT);
-        }
-        break;
-    case GPCMD_READ_10:
-    case GPCMD_READ_12:
-        {
-            int nb_sectors, lba;
-
-            if (packet[0] == GPCMD_READ_10)
-                nb_sectors = ube16_to_cpu(packet + 7);
-            else
-                nb_sectors = ube32_to_cpu(packet + 6);
-            lba = ube32_to_cpu(packet + 2);
-            if (nb_sectors == 0) {
-                ide_atapi_cmd_ok(s);
-                break;
-            }
-            ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
-        }
-        break;
-    case GPCMD_READ_CD:
-        {
-            int nb_sectors, lba, transfer_request;
-
-            nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8];
-            lba = ube32_to_cpu(packet + 2);
-            if (nb_sectors == 0) {
-                ide_atapi_cmd_ok(s);
-                break;
-            }
-            transfer_request = packet[9];
-            switch(transfer_request & 0xf8) {
-            case 0x00:
-                /* nothing */
-                ide_atapi_cmd_ok(s);
-                break;
-            case 0x10:
-                /* normal read */
-                ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
-                break;
-            case 0xf8:
-                /* read all data */
-                ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
-                break;
-            default:
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                    ASC_INV_FIELD_IN_CMD_PACKET);
-                break;
-            }
-        }
-        break;
-    case GPCMD_SEEK:
-        {
-            unsigned int lba;
-            uint64_t total_sectors;
-
-            bdrv_get_geometry(s->bs, &total_sectors);
-            total_sectors >>= 2;
-            if (total_sectors == 0) {
-                ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                                    ASC_MEDIUM_NOT_PRESENT);
-                break;
-            }
-            lba = ube32_to_cpu(packet + 2);
-            if (lba >= total_sectors) {
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                    ASC_LOGICAL_BLOCK_OOR);
-                break;
-            }
-            ide_atapi_cmd_ok(s);
-        }
-        break;
-    case GPCMD_START_STOP_UNIT:
-        {
-            int start, eject, err = 0;
-            start = packet[4] & 1;
-            eject = (packet[4] >> 1) & 1;
-
-            if (eject) {
-                err = bdrv_eject(s->bs, !start);
-            }
-
-            switch (err) {
-            case 0:
-                ide_atapi_cmd_ok(s);
-                break;
-            case -EBUSY:
-                ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                                    ASC_MEDIA_REMOVAL_PREVENTED);
-                break;
-            default:
-                ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                                    ASC_MEDIUM_NOT_PRESENT);
-                break;
-            }
-        }
-        break;
-    case GPCMD_MECHANISM_STATUS:
-        {
-            max_len = ube16_to_cpu(packet + 8);
-            cpu_to_ube16(buf, 0);
-            /* no current LBA */
-            buf[2] = 0;
-            buf[3] = 0;
-            buf[4] = 0;
-            buf[5] = 1;
-            cpu_to_ube16(buf + 6, 0);
-            ide_atapi_cmd_reply(s, 8, max_len);
-        }
-        break;
-    case GPCMD_READ_TOC_PMA_ATIP:
-        {
-            int format, msf, start_track, len;
-            uint64_t total_sectors;
-
-            bdrv_get_geometry(s->bs, &total_sectors);
-            total_sectors >>= 2;
-            if (total_sectors == 0) {
-                ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                                    ASC_MEDIUM_NOT_PRESENT);
-                break;
-            }
-            max_len = ube16_to_cpu(packet + 7);
-            format = packet[9] >> 6;
-            msf = (packet[1] >> 1) & 1;
-            start_track = packet[6];
-            switch(format) {
-            case 0:
-                len = cdrom_read_toc(total_sectors, buf, msf, start_track);
-                if (len < 0)
-                    goto error_cmd;
-                ide_atapi_cmd_reply(s, len, max_len);
-                break;
-            case 1:
-                /* multi session : only a single session defined */
-                memset(buf, 0, 12);
-                buf[1] = 0x0a;
-                buf[2] = 0x01;
-                buf[3] = 0x01;
-                ide_atapi_cmd_reply(s, 12, max_len);
-                break;
-            case 2:
-                len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track);
-                if (len < 0)
-                    goto error_cmd;
-                ide_atapi_cmd_reply(s, len, max_len);
-                break;
-            default:
-            error_cmd:
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                    ASC_INV_FIELD_IN_CMD_PACKET);
-                break;
-            }
-        }
-        break;
-    case GPCMD_READ_CDVD_CAPACITY:
-        {
-            uint64_t total_sectors;
-
-            bdrv_get_geometry(s->bs, &total_sectors);
-            total_sectors >>= 2;
-            if (total_sectors == 0) {
-                ide_atapi_cmd_error(s, SENSE_NOT_READY,
-                                    ASC_MEDIUM_NOT_PRESENT);
-                break;
-            }
-            /* NOTE: it is really the number of sectors minus 1 */
-            cpu_to_ube32(buf, total_sectors - 1);
-            cpu_to_ube32(buf + 4, 2048);
-            ide_atapi_cmd_reply(s, 8, 8);
-        }
-        break;
-    case GPCMD_READ_DVD_STRUCTURE:
-        {
-            int media = packet[1];
-            int format = packet[7];
-            int ret;
-
-            max_len = ube16_to_cpu(packet + 8);
-
-            if (format < 0xff) {
-                if (media_is_cd(s)) {
-                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                        ASC_INCOMPATIBLE_FORMAT);
-                    break;
-                } else if (!media_present(s)) {
-                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                        ASC_INV_FIELD_IN_CMD_PACKET);
-                    break;
-                }
-            }
-
-            memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
-                   IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
-
-            switch (format) {
-                case 0x00 ... 0x7f:
-                case 0xff:
-                    if (media == 0) {
-                        ret = ide_dvd_read_structure(s, format, packet, buf);
-
-                        if (ret < 0)
-                            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
-                        else
-                            ide_atapi_cmd_reply(s, ret, max_len);
-
-                        break;
-                    }
-                    /* TODO: BD support, fall through for now */
-
-                /* Generic disk structures */
-                case 0x80: /* TODO: AACS volume identifier */
-                case 0x81: /* TODO: AACS media serial number */
-                case 0x82: /* TODO: AACS media identifier */
-                case 0x83: /* TODO: AACS media key block */
-                case 0x90: /* TODO: List of recognized format layers */
-                case 0xc0: /* TODO: Write protection status */
-                default:
-                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                        ASC_INV_FIELD_IN_CMD_PACKET);
-                    break;
-            }
-        }
-        break;
-    case GPCMD_SET_SPEED:
-        ide_atapi_cmd_ok(s);
-        break;
-    case GPCMD_INQUIRY:
-        max_len = packet[4];
-        buf[0] = 0x05; /* CD-ROM */
-        buf[1] = 0x80; /* removable */
-        buf[2] = 0x00; /* ISO */
-        buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
-        buf[4] = 31; /* additional length */
-        buf[5] = 0; /* reserved */
-        buf[6] = 0; /* reserved */
-        buf[7] = 0; /* reserved */
-        padstr8(buf + 8, 8, "QEMU");
-        padstr8(buf + 16, 16, "QEMU DVD-ROM");
-        padstr8(buf + 32, 4, s->version);
-        ide_atapi_cmd_reply(s, 36, max_len);
-        break;
-    case GPCMD_GET_CONFIGURATION:
-        {
-            uint32_t len;
-            uint8_t index = 0;
-
-            /* only feature 0 is supported */
-            if (packet[2] != 0 || packet[3] != 0) {
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                    ASC_INV_FIELD_IN_CMD_PACKET);
-                break;
-            }
-
-            /* XXX: could result in alignment problems in some architectures */
-            max_len = ube16_to_cpu(packet + 7);
-
-            /*
-             * XXX: avoid overflow for io_buffer if max_len is bigger than
-             *      the size of that buffer (dimensioned to max number of
-             *      sectors to transfer at once)
-             *
-             *      Only a problem if the feature/profiles grow.
-             */
-            if (max_len > 512) /* XXX: assume 1 sector */
-                max_len = 512;
-
-            memset(buf, 0, max_len);
-            /* 
-             * the number of sectors from the media tells us which profile
-             * to use as current.  0 means there is no media
-             */
-            if (media_is_dvd(s))
-                cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
-            else if (media_is_cd(s))
-                cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
-
-            buf[10] = 0x02 | 0x01; /* persistent and current */
-            len = 12; /* headers: 8 + 4 */
-            len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM);
-            len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM);
-            cpu_to_ube32(buf, len - 4); /* data length */
-
-            ide_atapi_cmd_reply(s, len, max_len);
-            break;
-        }
-    case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
-        max_len = ube16_to_cpu(packet + 7);
-
-        if (packet[1] & 0x01) { /* polling */
-            /* We don't support any event class (yet). */
-            cpu_to_ube16(buf, 0x00); /* No event descriptor returned */
-            buf[2] = 0x80;           /* No Event Available (NEA) */
-            buf[3] = 0x00;           /* Empty supported event classes */
-            ide_atapi_cmd_reply(s, 4, max_len);
-        } else { /* asynchronous mode */
-            /* Only polling is supported, asynchronous mode is not. */
-            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                                ASC_INV_FIELD_IN_CMD_PACKET);
-        }
-        break;
-    default:
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
-                            ASC_ILLEGAL_OPCODE);
-        break;
-    }
-}
-
 static void ide_cfata_metadata_inquiry(IDEState *s)
 {
     uint16_t *p;
@@ -1609,9 +684,15 @@ static void cdrom_change_cb(void *opaque, int reason)
     bdrv_get_geometry(s->bs, &nb_sectors);
     s->nb_sectors = nb_sectors;
 
-    s->sense_key = SENSE_UNIT_ATTENTION;
-    s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
+    /*
+     * First indicate to the guest that a CD has been removed.  That's
+     * done on the next command the guest sends us.
+     *
+     * Then we set SENSE_UNIT_ATTENTION, by which the guest will
+     * detect a new CD in the drive.  See ide_atapi_cmd() for details.
+     */
     s->cdrom_changed = 1;
+    s->events.new_media = true;
     ide_set_irq(s->bus);
 }
 
@@ -2756,6 +1837,25 @@ static bool ide_drive_pio_state_needed(void *opaque)
     return (s->status & DRQ_STAT) != 0;
 }
 
+static bool ide_atapi_gesn_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return s->events.new_media || s->events.eject_request;
+}
+
+/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
+const VMStateDescription vmstate_ide_atapi_gesn_state = {
+    .name ="ide_drive/atapi/gesn_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_BOOL(events.new_media, IDEState),
+        VMSTATE_BOOL(events.eject_request, IDEState),
+    }
+};
+
 const VMStateDescription vmstate_ide_drive_pio_state = {
     .name = "ide_drive/pio_state",
     .version_id = 1,
@@ -2809,6 +1909,9 @@ const VMStateDescription vmstate_ide_drive = {
         {
             .vmsd = &vmstate_ide_drive_pio_state,
             .needed = ide_drive_pio_state_needed,
+        }, {
+            .vmsd = &vmstate_ide_atapi_gesn_state,
+            .needed = ide_atapi_gesn_needed,
         }, {
             /* empty */
         }
@@ -2826,3 +1929,17 @@ const VMStateDescription vmstate_ide_bus = {
         VMSTATE_END_OF_LIST()
     }
 };
+
+void ide_drive_get(DriveInfo **hd, int max_bus)
+{
+    int i;
+
+    if (drive_get_max_bus(IF_IDE) >= max_bus) {
+        fprintf(stderr, "qemu: too many IDE bus: %d\n", max_bus);
+        exit(1);
+    }
+
+    for(i = 0; i < max_bus * MAX_IDE_DEVS; i++) {
+        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+    }
+}
index fd3537e281aaceea2932fbc195ba485047093683..e44339b0789530f5f9174a2413236013ff5c45d2 100644 (file)
@@ -67,7 +67,6 @@
 #include <hw/isa.h>
 #include "block.h"
 #include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
index d533fb63b3bfa89ff84eef9cc980cea4b889535e..aa198b6b129f416d7ecc550970fbf3cba951efb2 100644 (file)
@@ -9,6 +9,7 @@
 #include <hw/ide.h>
 #include "block_int.h"
 #include "iorange.h"
+#include "dma.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -373,6 +374,11 @@ typedef int DMAFunc(IDEDMA *);
 typedef int DMAIntFunc(IDEDMA *, int);
 typedef void DMARestartFunc(void *, int, int);
 
+struct unreported_events {
+    bool eject_request;
+    bool new_media;
+};
+
 /* NOTE: IDEState represents in fact one drive */
 struct IDEState {
     IDEBus *bus;
@@ -408,6 +414,7 @@ struct IDEState {
     BlockDriverState *bs;
     char version[9];
     /* ATAPI specific */
+    struct unreported_events events;
     uint8_t sense_key;
     uint8_t asc;
     uint8_t cdrom_changed;
@@ -564,6 +571,15 @@ void ide_sector_write(IDEState *s);
 void ide_sector_read(IDEState *s);
 void ide_flush_cache(IDEState *s);
 
+void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
+                        EndTransferFunc *end_transfer_func);
+void ide_transfer_stop(IDEState *s);
+void ide_set_inactive(IDEState *s);
+
+/* hw/ide/atapi.c */
+void ide_atapi_cmd(IDEState *s);
+void ide_atapi_cmd_reply_end(IDEState *s);
+
 /* hw/ide/qdev.c */
 void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id);
 IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
index 8c59c5a47c0914f7eead8390ec10162515281b22..4ac745324cdf70d3da555cdd1d6bb29eb2992821 100644 (file)
@@ -27,7 +27,6 @@
 #include <hw/isa.h>
 #include "block.h"
 #include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
index c1b4caab5b4f80a9d8f17a26f1f685ad5394ade1..7107f6b3c213360ed3128ab427bc6b9e652051be 100644 (file)
@@ -27,7 +27,6 @@
 #include <hw/mac_dbdma.h>
 #include "block.h"
 #include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
index 2ceeb87c0c6c2bd6b3c8d893746abd9000e1a482..9fbbf0e78a7a9b95e65051c2fcb37bb865649c30 100644 (file)
@@ -27,7 +27,6 @@
 #include <hw/pcmcia.h>
 #include "block.h"
 #include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
index 82b24b673bbb88c7344e1480086d2694bcea828c..10f6f4063c0d22b07a07c54ccbc1596ae10cb10a 100644 (file)
@@ -25,7 +25,6 @@
 #include <hw/hw.h>
 #include "block.h"
 #include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
index 35168cb46970f70b904390637bc6d9cbd75155fb..65cb56c38c829bf036352b6f6b9276e3ef1f2c2d 100644 (file)
@@ -28,7 +28,6 @@
 #include <hw/isa.h>
 #include "block.h"
 #include "block_int.h"
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
index b0499408213047c61628186ac69f784cfd26409d..a6c27be82cc43c61ea3b8a84fc1cf6db3401d421 100644 (file)
@@ -10,7 +10,6 @@
 #include "sysbus.h"
 #include "primecell.h"
 #include "devices.h"
-#include "sysemu.h"
 #include "boards.h"
 #include "arm-misc.h"
 #include "net.h"
index 569327d1e96fb6f83266e9b80480da6aee7ecf9d..6c26e820e05a463d4de04c1b7688f8c2fee2aa49 100644 (file)
@@ -160,8 +160,9 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
                 s->irr &= ~mask;
             }
         } else {
-            /* edge triggered */
-            if (level) {
+            /* According to the 82093AA manual, we must ignore edge requests
+             * if the input pin is masked. */
+            if (level && !(entry & IOAPIC_LVT_MASKED)) {
                 s->irr |= mask;
                 ioapic_service(s);
             }
index d07aa410f7fd22e55292840e1f62e862ee9c02d4..27655436a0f423eb6d618ece3e6128121c1d8b54 100644 (file)
@@ -17,7 +17,6 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "hw.h"
-#include "sysemu.h"
 #include "monitor.h"
 #include "sysbus.h"
 #include "isa.h"
index b6ceddfba62e32e237e1bf5b8dcb318e2e6b2630..004c4add8c8aac7dd9b10d2ef9826f61cd8e5657 100644 (file)
@@ -103,7 +103,11 @@ static SysBusDeviceInfo kvmclock_info = {
 void kvmclock_create(void)
 {
     if (kvm_enabled() &&
-        first_cpu->cpuid_kvm_features & (1ULL << KVM_FEATURE_CLOCKSOURCE)) {
+        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE)
+#ifdef KVM_FEATURE_CLOCKSOURCE2
+        || (1ULL << KVM_FEATURE_CLOCKSOURCE2)
+#endif
+    )) {
         sysbus_create_simple("kvmclock", -1, NULL);
     }
 }
index af6949f1bcc80ccfed16baaa99153bddc9d354f9..2dc8d1854919b9a64e0d80f8731d82804583492f 100644 (file)
@@ -785,6 +785,12 @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
     case MAC_FLOW:
         s->mac_flow = val & 0xffff0000;
         break;
+    case MAC_VLAN1:
+        /* Writing to this register changes a condition for
+         * FrameTooLong bit in rx_status.  Since we do not set
+         * FrameTooLong anyway, just ignore write to this.
+         */
+        break;
     default:
         hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n",
                  s->mac_cmd & 0xf, val);
index 85190f0bfa4c955b3f1b8008d7168bde1a75c021..64629230cf2bee3d628cb8d4aae93a161a2e12be 100644 (file)
@@ -21,7 +21,6 @@
 #include "hw.h"
 #include "net.h"
 #include "flash.h"
-#include "sysemu.h"
 #include "devices.h"
 #include "boards.h"
 #include "loader.h"
index 6c811cf59090c1589a26b68c25753e4c53ecf3ba..be4df589d87a3d3ebc471997d6989bbfd9a80119 100644 (file)
@@ -853,6 +853,18 @@ static void lsi_do_msgout(LSIState *s)
 {
     uint8_t msg;
     int len;
+    uint32_t current_tag;
+    SCSIDevice *current_dev;
+    lsi_request *p, *p_next;
+    int id;
+
+    if (s->current) {
+        current_tag = s->current->tag;
+    } else {
+        current_tag = s->select_tag;
+    }
+    id = (current_tag >> 8) & 0xf;
+    current_dev = s->bus.devs[id];
 
     DPRINTF("MSG out len=%d\n", s->dbc);
     while (s->dbc) {
@@ -898,6 +910,51 @@ static void lsi_do_msgout(LSIState *s)
             BADF("ORDERED queue not implemented\n");
             s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
             break;
+        case 0x0d:
+            /* The ABORT TAG message clears the current I/O process only. */
+            DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
+            current_dev->info->cancel_io(current_dev, current_tag);
+            lsi_disconnect(s);
+            break;
+        case 0x06:
+        case 0x0e:
+        case 0x0c:
+            /* The ABORT message clears all I/O processes for the selecting
+               initiator on the specified logical unit of the target. */
+            if (msg == 0x06) {
+                DPRINTF("MSG: ABORT tag=0x%x\n", current_tag);
+            }
+            /* The CLEAR QUEUE message clears all I/O processes for all
+               initiators on the specified logical unit of the target. */
+            if (msg == 0x0e) {
+                DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag);
+            }
+            /* The BUS DEVICE RESET message clears all I/O processes for all
+               initiators on all logical units of the target. */
+            if (msg == 0x0c) {
+                DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
+            }
+
+            /* clear the current I/O process */
+            current_dev->info->cancel_io(current_dev, current_tag);
+
+            /* As the current implemented devices scsi_disk and scsi_generic
+               only support one LUN, we don't need to keep track of LUNs.
+               Clearing I/O processes for other initiators could be possible
+               for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX
+               device, but this is currently not implemented (and seems not
+               to be really necessary). So let's simply clear all queued
+               commands for the current device: */
+            id = current_tag & 0x0000ff00;
+            QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
+                if ((p->tag & 0x0000ff00) == id) {
+                    current_dev->info->cancel_io(current_dev, p->tag);
+                    QTAILQ_REMOVE(&s->queue, p, next);
+                }
+            }
+
+            lsi_disconnect(s);
+            break;
         default:
             if ((msg & 0x80) == 0) {
                 goto bad;
index 9f39d6bbf0d567a7b869bb1ea3e129b507e0033d..537c0f7b166d6f47c2e9956e373b68830f21550b 100644 (file)
@@ -585,28 +585,18 @@ static CPUReadMemoryFunc * const nvram_read[] = {
     &nvram_readl,
 };
 
-static void m48t59_save(QEMUFile *f, void *opaque)
-{
-    M48t59State *s = opaque;
-
-    qemu_put_8s(f, &s->lock);
-    qemu_put_be16s(f, &s->addr);
-    qemu_put_buffer(f, s->buffer, s->size);
-}
-
-static int m48t59_load(QEMUFile *f, void *opaque, int version_id)
-{
-    M48t59State *s = opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    qemu_get_8s(f, &s->lock);
-    qemu_get_be16s(f, &s->addr);
-    qemu_get_buffer(f, s->buffer, s->size);
-
-    return 0;
-}
+static const VMStateDescription vmstate_m48t59 = {
+    .name = "m48t59",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(lock, M48t59State),
+        VMSTATE_UINT16(addr, M48t59State),
+        VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static void m48t59_reset_common(M48t59State *NVRAM)
 {
@@ -696,7 +686,7 @@ static void m48t59_init_common(M48t59State *s)
     }
     qemu_get_timedate(&s->alarm, 0);
 
-    register_savevm(NULL, "m48t59", -1, 1, m48t59_save, m48t59_load, s);
+    vmstate_register(NULL, -1, &vmstate_m48t59, s);
 }
 
 static int m48t59_init_isa1(ISADevice *dev)
index 5680fa9c1c1a2ebdd6b14c151644d901246f5dc4..ed4458e3bb93f53a86f7191b42a90bbbf6da6c23 100644 (file)
@@ -165,6 +165,10 @@ typedef struct DBDMA_channel {
     int processing;
 } DBDMA_channel;
 
+typedef struct {
+    DBDMA_channel channels[DBDMA_CHANNELS];
+} DBDMAState;
+
 #ifdef DEBUG_DBDMA
 static void dump_dbdma_cmd(dbdma_cmd *cmd)
 {
@@ -617,31 +621,34 @@ static void channel_run(DBDMA_channel *ch)
     }
 }
 
-static void DBDMA_run (DBDMA_channel *ch)
+static void DBDMA_run(DBDMAState *s)
 {
     int channel;
 
-    for (channel = 0; channel < DBDMA_CHANNELS; channel++, ch++) {
-            uint32_t status = ch->regs[DBDMA_STATUS];
-            if (!ch->processing && (status & RUN) && (status & ACTIVE))
-                channel_run(ch);
+    for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
+        DBDMA_channel *ch = &s->channels[channel];
+        uint32_t status = ch->regs[DBDMA_STATUS];
+        if (!ch->processing && (status & RUN) && (status & ACTIVE)) {
+            channel_run(ch);
+        }
     }
 }
 
 static void DBDMA_run_bh(void *opaque)
 {
-    DBDMA_channel *ch = opaque;
+    DBDMAState *s = opaque;
 
     DBDMA_DPRINTF("DBDMA_run_bh\n");
 
-    DBDMA_run(ch);
+    DBDMA_run(s);
 }
 
 void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
                             DBDMA_rw rw, DBDMA_flush flush,
                             void *opaque)
 {
-    DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan;
+    DBDMAState *s = dbdma;
+    DBDMA_channel *ch = &s->channels[nchan];
 
     DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
 
@@ -700,7 +707,8 @@ static void dbdma_writel (void *opaque,
                           target_phys_addr_t addr, uint32_t value)
 {
     int channel = addr >> DBDMA_CHANNEL_SHIFT;
-    DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
+    DBDMAState *s = opaque;
+    DBDMA_channel *ch = &s->channels[channel];
     int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
 
     DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
@@ -749,7 +757,8 @@ static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
 {
     uint32_t value;
     int channel = addr >> DBDMA_CHANNEL_SHIFT;
-    DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
+    DBDMAState *s = opaque;
+    DBDMA_channel *ch = &s->channels[channel];
     int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
 
     value = ch->regs[reg];
@@ -801,49 +810,47 @@ static CPUReadMemoryFunc * const dbdma_read[] = {
     dbdma_readl,
 };
 
-static void dbdma_save(QEMUFile *f, void *opaque)
-{
-    DBDMA_channel *s = opaque;
-    unsigned int i, j;
-
-    for (i = 0; i < DBDMA_CHANNELS; i++)
-        for (j = 0; j < DBDMA_REGS; j++)
-            qemu_put_be32s(f, &s[i].regs[j]);
-}
-
-static int dbdma_load(QEMUFile *f, void *opaque, int version_id)
-{
-    DBDMA_channel *s = opaque;
-    unsigned int i, j;
-
-    if (version_id != 2)
-        return -EINVAL;
-
-    for (i = 0; i < DBDMA_CHANNELS; i++)
-        for (j = 0; j < DBDMA_REGS; j++)
-            qemu_get_be32s(f, &s[i].regs[j]);
+static const VMStateDescription vmstate_dbdma_channel = {
+    .name = "dbdma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-    return 0;
-}
+static const VMStateDescription vmstate_dbdma = {
+    .name = "dbdma",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1,
+                             vmstate_dbdma_channel, DBDMA_channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static void dbdma_reset(void *opaque)
 {
-    DBDMA_channel *s = opaque;
+    DBDMAState *s = opaque;
     int i;
 
     for (i = 0; i < DBDMA_CHANNELS; i++)
-        memset(s[i].regs, 0, DBDMA_SIZE);
+        memset(s->channels[i].regs, 0, DBDMA_SIZE);
 }
 
 void* DBDMA_init (int *dbdma_mem_index)
 {
-    DBDMA_channel *s;
+    DBDMAState *s;
 
-    s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS);
+    s = qemu_mallocz(sizeof(DBDMAState));
 
     *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s,
                                               DEVICE_LITTLE_ENDIAN);
-    register_savevm(NULL, "dbdma", -1, 1, dbdma_save, dbdma_load, s);
+    vmstate_register(NULL, -1, &vmstate_dbdma, s);
     qemu_register_reset(dbdma_reset, s);
 
     dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
index c2a2fc21e49ba137c256b0e57ebff82561fc51e2..61e53d28b4d2bdaeec422f4b05d63e92a450ccf6 100644 (file)
@@ -38,7 +38,7 @@
 #endif
 
 struct MacIONVRAMState {
-    target_phys_addr_t size;
+    uint32_t size;
     int mem_index;
     unsigned int it_shift;
     uint8_t *data;
@@ -105,24 +105,17 @@ static CPUReadMemoryFunc * const nvram_read[] = {
     &macio_nvram_readb,
 };
 
-static void macio_nvram_save(QEMUFile *f, void *opaque)
-{
-    MacIONVRAMState *s = (MacIONVRAMState *)opaque;
-
-    qemu_put_buffer(f, s->data, s->size);
-}
-
-static int macio_nvram_load(QEMUFile *f, void *opaque, int version_id)
-{
-    MacIONVRAMState *s = (MacIONVRAMState *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    qemu_get_buffer(f, s->data, s->size);
+static const VMStateDescription vmstate_macio_nvram = {
+    .name = "macio_nvram",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-    return 0;
-}
 
 static void macio_nvram_reset(void *opaque)
 {
@@ -141,8 +134,7 @@ MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size,
     s->mem_index = cpu_register_io_memory(nvram_read, nvram_write, s,
                                           DEVICE_NATIVE_ENDIAN);
     *mem_index = s->mem_index;
-    register_savevm(NULL, "macio_nvram", -1, 1, macio_nvram_save,
-                    macio_nvram_load, s);
+    vmstate_register(NULL, -1, &vmstate_macio_nvram, s);
     qemu_register_reset(macio_nvram_reset, s);
 
     return s;
index 50691ca41ef57c48c9f3b92d5430f343aa7d0a9a..4792f0e3ed1671b5af217a5c1cbf3e4d7e81fe5f 100644 (file)
@@ -14,7 +14,6 @@
 #include "net.h"
 #include "devices.h"
 #include "boards.h"
-#include "sysemu.h"
 #include "flash.h"
 #include "blockdev.h"
 #include "sysbus.h"
index 2844665ba327b5b98d106e90e4f8d3a206ee363b..70cd1af24f0446cba8cf27f1064ed8c3fe95cf03 100644 (file)
@@ -15,7 +15,7 @@ typedef struct {
     uint8_t tb1, rb2, rb3;
     int cycle;
 
-    int input[8];
+    uint8_t input[8];
     int inputs, com;
 } MAX111xState;
 
@@ -94,36 +94,22 @@ static uint32_t max111x_transfer(SSISlave *dev, uint32_t value)
     return max111x_read(s);
 }
 
-static void max111x_save(QEMUFile *f, void *opaque)
-{
-    MAX111xState *s = (MAX111xState *) opaque;
-    int i;
-
-    qemu_put_8s(f, &s->tb1);
-    qemu_put_8s(f, &s->rb2);
-    qemu_put_8s(f, &s->rb3);
-    qemu_put_be32(f, s->inputs);
-    qemu_put_be32(f, s->com);
-    for (i = 0; i < s->inputs; i ++)
-        qemu_put_byte(f, s->input[i]);
-}
-
-static int max111x_load(QEMUFile *f, void *opaque, int version_id)
-{
-    MAX111xState *s = (MAX111xState *) opaque;
-    int i;
-
-    qemu_get_8s(f, &s->tb1);
-    qemu_get_8s(f, &s->rb2);
-    qemu_get_8s(f, &s->rb3);
-    if (s->inputs != qemu_get_be32(f))
-        return -EINVAL;
-    s->com = qemu_get_be32(f);
-    for (i = 0; i < s->inputs; i ++)
-        s->input[i] = qemu_get_byte(f);
-
-    return 0;
-}
+static const VMStateDescription vmstate_max111x = {
+    .name = "max111x",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(tb1, MAX111xState),
+        VMSTATE_UINT8(rb2, MAX111xState),
+        VMSTATE_UINT8(rb3, MAX111xState),
+        VMSTATE_INT32_EQUAL(inputs, MAX111xState),
+        VMSTATE_INT32(com, MAX111xState),
+        VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs,
+                                   vmstate_info_uint8, uint8_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int max111x_init(SSISlave *dev, int inputs)
 {
@@ -143,8 +129,7 @@ static int max111x_init(SSISlave *dev, int inputs)
     s->input[7] = 0x80;
     s->com = 0;
 
-    register_savevm(&dev->qdev, "max111x", -1, 0,
-                    max111x_save, max111x_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_max111x, s);
     return 0;
 }
 
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
new file mode 100644 (file)
index 0000000..6c9e318
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/ac97.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "audio/audio.h"
+#include "qemu-error.h"
+
+enum {
+    R_AC97_CTRL = 0,
+    R_AC97_ADDR,
+    R_AC97_DATAOUT,
+    R_AC97_DATAIN,
+    R_D_CTRL,
+    R_D_ADDR,
+    R_D_REMAINING,
+    R_RESERVED,
+    R_U_CTRL,
+    R_U_ADDR,
+    R_U_REMAINING,
+    R_MAX
+};
+
+enum {
+    AC97_CTRL_RQEN  = (1<<0),
+    AC97_CTRL_WRITE = (1<<1),
+};
+
+enum {
+    CTRL_EN = (1<<0),
+};
+
+struct MilkymistAC97State {
+    SysBusDevice busdev;
+
+    QEMUSoundCard card;
+    SWVoiceIn *voice_in;
+    SWVoiceOut *voice_out;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq crrequest_irq;
+    qemu_irq crreply_irq;
+    qemu_irq dmar_irq;
+    qemu_irq dmaw_irq;
+};
+typedef struct MilkymistAC97State MilkymistAC97State;
+
+static void update_voices(MilkymistAC97State *s)
+{
+    if (s->regs[R_D_CTRL] & CTRL_EN) {
+        AUD_set_active_out(s->voice_out, 1);
+    } else {
+        AUD_set_active_out(s->voice_out, 0);
+    }
+
+    if (s->regs[R_U_CTRL] & CTRL_EN) {
+        AUD_set_active_in(s->voice_in, 1);
+    } else {
+        AUD_set_active_in(s->voice_in, 0);
+    }
+}
+
+static uint32_t ac97_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistAC97State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_AC97_CTRL:
+    case R_AC97_ADDR:
+    case R_AC97_DATAOUT:
+    case R_AC97_DATAIN:
+    case R_D_CTRL:
+    case R_D_ADDR:
+    case R_D_REMAINING:
+    case R_U_CTRL:
+    case R_U_ADDR:
+    case R_U_REMAINING:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_ac97: read access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_ac97_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistAC97State *s = opaque;
+
+    trace_milkymist_ac97_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_AC97_CTRL:
+        /* always raise an IRQ according to the direction */
+        if (value & AC97_CTRL_RQEN) {
+            if (value & AC97_CTRL_WRITE) {
+                trace_milkymist_ac97_pulse_irq_crrequest();
+                qemu_irq_pulse(s->crrequest_irq);
+            } else {
+                trace_milkymist_ac97_pulse_irq_crreply();
+                qemu_irq_pulse(s->crreply_irq);
+            }
+        }
+
+        /* RQEN is self clearing */
+        s->regs[addr] = value & ~AC97_CTRL_RQEN;
+        break;
+    case R_D_CTRL:
+    case R_U_CTRL:
+        s->regs[addr] = value;
+        update_voices(s);
+        break;
+    case R_AC97_ADDR:
+    case R_AC97_DATAOUT:
+    case R_AC97_DATAIN:
+    case R_D_ADDR:
+    case R_D_REMAINING:
+    case R_U_ADDR:
+    case R_U_REMAINING:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_ac97: write access to unkown register 0x"
+                TARGET_FMT_plx, addr);
+        break;
+    }
+
+}
+
+static CPUReadMemoryFunc * const ac97_read_fn[] = {
+    NULL,
+    NULL,
+    &ac97_read,
+};
+
+static CPUWriteMemoryFunc * const ac97_write_fn[] = {
+    NULL,
+    NULL,
+    &ac97_write,
+};
+
+static void ac97_in_cb(void *opaque, int avail_b)
+{
+    MilkymistAC97State *s = opaque;
+    uint8_t buf[4096];
+    uint32_t remaining = s->regs[R_U_REMAINING];
+    int temp = audio_MIN(remaining, avail_b);
+    uint32_t addr = s->regs[R_U_ADDR];
+    int transferred = 0;
+
+    trace_milkymist_ac97_in_cb(avail_b, remaining);
+
+    /* prevent from raising an IRQ */
+    if (temp == 0) {
+        return;
+    }
+
+    while (temp) {
+        int acquired, to_copy;
+
+        to_copy = audio_MIN(temp, sizeof(buf));
+        acquired = AUD_read(s->voice_in, buf, to_copy);
+        if (!acquired) {
+            break;
+        }
+
+        cpu_physical_memory_write(addr, buf, acquired);
+
+        temp -= acquired;
+        addr += acquired;
+        transferred += acquired;
+    }
+
+    trace_milkymist_ac97_in_cb_transferred(transferred);
+
+    s->regs[R_U_ADDR] = addr;
+    s->regs[R_U_REMAINING] -= transferred;
+
+    if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) {
+        trace_milkymist_ac97_pulse_irq_dmaw();
+        qemu_irq_pulse(s->dmaw_irq);
+    }
+}
+
+static void ac97_out_cb(void *opaque, int free_b)
+{
+    MilkymistAC97State *s = opaque;
+    uint8_t buf[4096];
+    uint32_t remaining = s->regs[R_D_REMAINING];
+    int temp = audio_MIN(remaining, free_b);
+    uint32_t addr = s->regs[R_D_ADDR];
+    int transferred = 0;
+
+    trace_milkymist_ac97_out_cb(free_b, remaining);
+
+    /* prevent from raising an IRQ */
+    if (temp == 0) {
+        return;
+    }
+
+    while (temp) {
+        int copied, to_copy;
+
+        to_copy = audio_MIN(temp, sizeof(buf));
+        cpu_physical_memory_read(addr, buf, to_copy);
+        copied = AUD_write(s->voice_out, buf, to_copy);
+        if (!copied) {
+            break;
+        }
+        temp -= copied;
+        addr += copied;
+        transferred += copied;
+    }
+
+    trace_milkymist_ac97_out_cb_transferred(transferred);
+
+    s->regs[R_D_ADDR] = addr;
+    s->regs[R_D_REMAINING] -= transferred;
+
+    if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) {
+        trace_milkymist_ac97_pulse_irq_dmar();
+        qemu_irq_pulse(s->dmar_irq);
+    }
+}
+
+static void milkymist_ac97_reset(DeviceState *d)
+{
+    MilkymistAC97State *s = container_of(d, MilkymistAC97State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    AUD_set_active_in(s->voice_in, 0);
+    AUD_set_active_out(s->voice_out, 0);
+}
+
+static int ac97_post_load(void *opaque, int version_id)
+{
+    MilkymistAC97State *s = opaque;
+
+    update_voices(s);
+
+    return 0;
+}
+
+static int milkymist_ac97_init(SysBusDevice *dev)
+{
+    MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev);
+    int ac97_regs;
+
+    struct audsettings as;
+    sysbus_init_irq(dev, &s->crrequest_irq);
+    sysbus_init_irq(dev, &s->crreply_irq);
+    sysbus_init_irq(dev, &s->dmar_irq);
+    sysbus_init_irq(dev, &s->dmaw_irq);
+
+    AUD_register_card("Milkymist AC'97", &s->card);
+
+    as.freq = 48000;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 1;
+
+    s->voice_in = AUD_open_in(&s->card, s->voice_in,
+            "mm_ac97.in", s, ac97_in_cb, &as);
+    s->voice_out = AUD_open_out(&s->card, s->voice_out,
+            "mm_ac97.out", s, ac97_out_cb, &as);
+
+    ac97_regs = cpu_register_io_memory(ac97_read_fn, ac97_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, ac97_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_ac97 = {
+    .name = "milkymist-ac97",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ac97_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_ac97_info = {
+    .init = milkymist_ac97_init,
+    .qdev.name  = "milkymist-ac97",
+    .qdev.size  = sizeof(MilkymistAC97State),
+    .qdev.vmsd  = &vmstate_milkymist_ac97,
+    .qdev.reset = milkymist_ac97_reset,
+};
+
+static void milkymist_ac97_register(void)
+{
+    sysbus_register_withprop(&milkymist_ac97_info);
+}
+
+device_init(milkymist_ac97_register)
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
new file mode 100644 (file)
index 0000000..c0962fb
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  QEMU model of the Milkymist High Performance Dynamic Memory Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/hpdmc.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-error.h"
+
+enum {
+    R_SYSTEM = 0,
+    R_BYPASS,
+    R_TIMING,
+    R_IODELAY,
+    R_MAX
+};
+
+enum {
+    IODELAY_DQSDELAY_RDY = (1<<5),
+    IODELAY_PLL1_LOCKED  = (1<<6),
+    IODELAY_PLL2_LOCKED  = (1<<7),
+};
+
+struct MilkymistHpdmcState {
+    SysBusDevice busdev;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistHpdmcState MilkymistHpdmcState;
+
+static uint32_t hpdmc_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistHpdmcState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SYSTEM:
+    case R_BYPASS:
+    case R_TIMING:
+    case R_IODELAY:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_hpdmc: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_hpdmc_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void hpdmc_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistHpdmcState *s = opaque;
+
+    trace_milkymist_hpdmc_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SYSTEM:
+    case R_BYPASS:
+    case R_TIMING:
+        s->regs[addr] = value;
+        break;
+    case R_IODELAY:
+        /* ignore writes */
+        break;
+
+    default:
+        error_report("milkymist_hpdmc: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const hpdmc_read_fn[] = {
+    NULL,
+    NULL,
+    &hpdmc_read,
+};
+
+static CPUWriteMemoryFunc * const hpdmc_write_fn[] = {
+    NULL,
+    NULL,
+    &hpdmc_write,
+};
+
+static void milkymist_hpdmc_reset(DeviceState *d)
+{
+    MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
+                         | IODELAY_PLL2_LOCKED;
+}
+
+static int milkymist_hpdmc_init(SysBusDevice *dev)
+{
+    MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev);
+    int hpdmc_regs;
+
+    hpdmc_regs = cpu_register_io_memory(hpdmc_read_fn, hpdmc_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, hpdmc_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_hpdmc = {
+    .name = "milkymist-hpdmc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_hpdmc_info = {
+    .init = milkymist_hpdmc_init,
+    .qdev.name  = "milkymist-hpdmc",
+    .qdev.size  = sizeof(MilkymistHpdmcState),
+    .qdev.vmsd  = &vmstate_milkymist_hpdmc,
+    .qdev.reset = milkymist_hpdmc_reset,
+};
+
+static void milkymist_hpdmc_register(void)
+{
+    sysbus_register_withprop(&milkymist_hpdmc_info);
+}
+
+device_init(milkymist_hpdmc_register)
diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h
new file mode 100644 (file)
index 0000000..20de68e
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef QEMU_HW_MILKYMIST_H
+#define QEMU_HW_MILKYMIST_H
+
+#include "qdev.h"
+#include "qdev-addr.h"
+
+static inline DeviceState *milkymist_uart_create(target_phys_addr_t base,
+        qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-uart");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_hpdmc_create(target_phys_addr_t base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-hpdmc");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_memcard_create(target_phys_addr_t base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-memcard");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_vgafb_create(target_phys_addr_t base,
+        uint32_t fb_offset, uint32_t fb_mask)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-vgafb");
+    qdev_prop_set_uint32(dev, "fb_offset", fb_offset);
+    qdev_prop_set_uint32(dev, "fb_mask", fb_mask);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_sysctl_create(target_phys_addr_t base,
+        qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq,
+        uint32_t freq_hz, uint32_t system_id, uint32_t capabilities,
+        uint32_t gpio_strappings)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-sysctl");
+    qdev_prop_set_uint32(dev, "frequency", freq_hz);
+    qdev_prop_set_uint32(dev, "systemid", system_id);
+    qdev_prop_set_uint32(dev, "capabilities", capabilities);
+    qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, gpio_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, timer0_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 2, timer1_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_pfpu_create(target_phys_addr_t base,
+        qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-pfpu");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+    return dev;
+}
+
+#ifdef CONFIG_OPENGL
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+#endif
+
+static inline DeviceState *milkymist_tmu2_create(target_phys_addr_t base,
+        qemu_irq irq)
+{
+#ifdef CONFIG_OPENGL
+    DeviceState *dev;
+    Display *d;
+    GLXFBConfig *configs;
+    int nelements;
+    int ver_major, ver_minor;
+
+    if (display_type == DT_NOGRAPHIC) {
+        return NULL;
+    }
+
+    /* check that GLX will work */
+    d = XOpenDisplay(NULL);
+    if (d == NULL) {
+        return NULL;
+    }
+
+    if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
+        /* Yeah, sometimes getting the GLX version can fail.
+         * Isn't X beautiful? */
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
+        printf("Your GLX version is %d.%d,"
+          "but TMU emulation needs at least 1.3. TMU disabled.\n",
+          ver_major, ver_minor);
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    XFree(configs);
+    XCloseDisplay(d);
+
+    dev = qdev_create(NULL, "milkymist-tmu2");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+#else
+    return NULL;
+#endif
+}
+
+static inline DeviceState *milkymist_ac97_create(target_phys_addr_t base,
+        qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq,
+        qemu_irq dmaw_irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-ac97");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, crrequest_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, crreply_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 2, dmar_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 3, dmaw_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_minimac_create(target_phys_addr_t base,
+        qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    qemu_check_nic_model(&nd_table[0], "minimac");
+    dev = qdev_create(NULL, "milkymist-minimac");
+    qdev_set_nic_properties(dev, &nd_table[0]);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_minimac2_create(target_phys_addr_t base,
+        target_phys_addr_t buffers_base, qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    qemu_check_nic_model(&nd_table[0], "minimac2");
+    dev = qdev_create(NULL, "milkymist-minimac2");
+    qdev_prop_set_taddr(dev, "buffers_base", buffers_base);
+    qdev_set_nic_properties(dev, &nd_table[0]);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_softusb_create(target_phys_addr_t base,
+        qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size,
+        uint32_t dmem_base, uint32_t dmem_size)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-softusb");
+    qdev_prop_set_uint32(dev, "pmem_base", pmem_base);
+    qdev_prop_set_uint32(dev, "pmem_size", pmem_size);
+    qdev_prop_set_uint32(dev, "dmem_base", dmem_base);
+    qdev_prop_set_uint32(dev, "dmem_size", dmem_size);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+#endif /* QEMU_HW_MILKYMIST_H */
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
new file mode 100644 (file)
index 0000000..06077af
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *  QEMU model of the Milkymist SD Card Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/memcard.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu-error.h"
+#include "blockdev.h"
+#include "sd.h"
+
+enum {
+    ENABLE_CMD_TX   = (1<<0),
+    ENABLE_CMD_RX   = (1<<1),
+    ENABLE_DAT_TX   = (1<<2),
+    ENABLE_DAT_RX   = (1<<3),
+};
+
+enum {
+    PENDING_CMD_TX   = (1<<0),
+    PENDING_CMD_RX   = (1<<1),
+    PENDING_DAT_TX   = (1<<2),
+    PENDING_DAT_RX   = (1<<3),
+};
+
+enum {
+    START_CMD_TX    = (1<<0),
+    START_DAT_RX    = (1<<1),
+};
+
+enum {
+    R_CLK2XDIV = 0,
+    R_ENABLE,
+    R_PENDING,
+    R_START,
+    R_CMD,
+    R_DAT,
+    R_MAX
+};
+
+struct MilkymistMemcardState {
+    SysBusDevice busdev;
+    SDState *card;
+
+    int command_write_ptr;
+    int response_read_ptr;
+    int response_len;
+    int ignore_next_cmd;
+    int enabled;
+    uint8_t command[6];
+    uint8_t response[17];
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistMemcardState MilkymistMemcardState;
+
+static void update_pending_bits(MilkymistMemcardState *s)
+{
+    /* transmits are instantaneous, thus tx pending bits are never set */
+    s->regs[R_PENDING] = 0;
+    /* if rx is enabled the corresponding pending bits are always set */
+    if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
+        s->regs[R_PENDING] |= PENDING_CMD_RX;
+    }
+    if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
+        s->regs[R_PENDING] |= PENDING_DAT_RX;
+    }
+}
+
+static void memcard_sd_command(MilkymistMemcardState *s)
+{
+    SDRequest req;
+
+    req.cmd = s->command[0] & 0x3f;
+    req.arg = (s->command[1] << 24) | (s->command[2] << 16)
+              | (s->command[3] << 8) | s->command[4];
+    req.crc = s->command[5];
+
+    s->response[0] = req.cmd;
+    s->response_len = sd_do_command(s->card, &req, s->response+1);
+    s->response_read_ptr = 0;
+
+    if (s->response_len == 16) {
+        /* R2 response */
+        s->response[0] = 0x3f;
+        s->response_len += 1;
+    } else if (s->response_len == 4) {
+        /* no crc calculation, insert dummy byte */
+        s->response[5] = 0;
+        s->response_len += 2;
+    }
+
+    if (req.cmd == 0) {
+        /* next write is a dummy byte to clock the initialization of the sd
+         * card */
+        s->ignore_next_cmd = 1;
+    }
+}
+
+static uint32_t memcard_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistMemcardState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CMD:
+        if (!s->enabled) {
+            r = 0xff;
+        } else {
+            r = s->response[s->response_read_ptr++];
+            if (s->response_read_ptr > s->response_len) {
+                error_report("milkymist_memcard: "
+                        "read more cmd bytes than available. Clipping.");
+                s->response_read_ptr = 0;
+            }
+        }
+        break;
+    case R_DAT:
+        if (!s->enabled) {
+            r = 0xffffffff;
+        } else {
+            r = 0;
+            r |= sd_read_data(s->card) << 24;
+            r |= sd_read_data(s->card) << 16;
+            r |= sd_read_data(s->card) << 8;
+            r |= sd_read_data(s->card);
+        }
+        break;
+    case R_CLK2XDIV:
+    case R_ENABLE:
+    case R_PENDING:
+    case R_START:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_memcard: read access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_memcard_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void memcard_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistMemcardState *s = opaque;
+
+    trace_milkymist_memcard_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_PENDING:
+        /* clear rx pending bits */
+        s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
+        update_pending_bits(s);
+        break;
+    case R_CMD:
+        if (!s->enabled) {
+            break;
+        }
+        if (s->ignore_next_cmd) {
+            s->ignore_next_cmd = 0;
+            break;
+        }
+        s->command[s->command_write_ptr] = value & 0xff;
+        s->command_write_ptr = (s->command_write_ptr + 1) % 6;
+        if (s->command_write_ptr == 0) {
+            memcard_sd_command(s);
+        }
+        break;
+    case R_DAT:
+        if (!s->enabled) {
+            break;
+        }
+        sd_write_data(s->card, (value >> 24) & 0xff);
+        sd_write_data(s->card, (value >> 16) & 0xff);
+        sd_write_data(s->card, (value >> 8) & 0xff);
+        sd_write_data(s->card, value & 0xff);
+        break;
+    case R_ENABLE:
+        s->regs[addr] = value;
+        update_pending_bits(s);
+        break;
+    case R_CLK2XDIV:
+    case R_START:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_memcard: write access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const memcard_read_fn[] = {
+    NULL,
+    NULL,
+    &memcard_read,
+};
+
+static CPUWriteMemoryFunc * const memcard_write_fn[] = {
+    NULL,
+    NULL,
+    &memcard_write,
+};
+
+static void milkymist_memcard_reset(DeviceState *d)
+{
+    MilkymistMemcardState *s =
+            container_of(d, MilkymistMemcardState, busdev.qdev);
+    int i;
+
+    s->command_write_ptr = 0;
+    s->response_read_ptr = 0;
+    s->response_len = 0;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_memcard_init(SysBusDevice *dev)
+{
+    MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev);
+    DriveInfo *dinfo;
+    int memcard_regs;
+
+    dinfo = drive_get_next(IF_SD);
+    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
+
+    memcard_regs = cpu_register_io_memory(memcard_read_fn, memcard_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, memcard_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_memcard = {
+    .name = "milkymist-memcard",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
+        VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
+        VMSTATE_INT32(response_len, MilkymistMemcardState),
+        VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
+        VMSTATE_INT32(enabled, MilkymistMemcardState),
+        VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
+        VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_memcard_info = {
+    .init = milkymist_memcard_init,
+    .qdev.name  = "milkymist-memcard",
+    .qdev.size  = sizeof(MilkymistMemcardState),
+    .qdev.vmsd  = &vmstate_milkymist_memcard,
+    .qdev.reset = milkymist_memcard_reset,
+};
+
+static void milkymist_memcard_register(void)
+{
+    sysbus_register_withprop(&milkymist_memcard_info);
+}
+
+device_init(milkymist_memcard_register)
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
new file mode 100644 (file)
index 0000000..c4e2818
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ *  QEMU model of the Milkymist minimac2 block.
+ *
+ *  Copyright (c) 2011 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "net.h"
+#include "qemu-error.h"
+#include "qdev-addr.h"
+
+#include <zlib.h>
+
+enum {
+    R_SETUP = 0,
+    R_MDIO,
+    R_STATE0,
+    R_COUNT0,
+    R_STATE1,
+    R_COUNT1,
+    R_TXCOUNT,
+    R_MAX
+};
+
+enum {
+    SETUP_PHY_RST = (1<<0),
+};
+
+enum {
+    MDIO_DO  = (1<<0),
+    MDIO_DI  = (1<<1),
+    MDIO_OE  = (1<<2),
+    MDIO_CLK = (1<<3),
+};
+
+enum {
+    STATE_EMPTY   = 0,
+    STATE_LOADED  = 1,
+    STATE_PENDING = 2,
+};
+
+enum {
+    MDIO_OP_WRITE = 1,
+    MDIO_OP_READ  = 2,
+};
+
+enum mdio_state {
+    MDIO_STATE_IDLE,
+    MDIO_STATE_READING,
+    MDIO_STATE_WRITING,
+};
+
+enum {
+    R_PHY_ID1  = 2,
+    R_PHY_ID2  = 3,
+    R_PHY_MAX  = 32
+};
+
+#define MINIMAC2_MTU 1530
+#define MINIMAC2_BUFFER_SIZE 2048
+
+struct MilkymistMinimac2MdioState {
+    int last_clk;
+    int count;
+    uint32_t data;
+    uint16_t data_out;
+    int state;
+
+    uint8_t phy_addr;
+    uint8_t reg_addr;
+};
+typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
+
+struct MilkymistMinimac2State {
+    SysBusDevice busdev;
+    NICState *nic;
+    NICConf conf;
+    char *phy_model;
+    target_phys_addr_t buffers_base;
+
+    qemu_irq rx_irq;
+    qemu_irq tx_irq;
+
+    uint32_t regs[R_MAX];
+
+    MilkymistMinimac2MdioState mdio;
+
+    uint16_t phy_regs[R_PHY_MAX];
+
+    uint8_t *rx0_buf;
+    uint8_t *rx1_buf;
+    uint8_t *tx_buf;
+};
+typedef struct MilkymistMinimac2State MilkymistMinimac2State;
+
+static const uint8_t preamble_sfd[] = {
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
+};
+
+static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
+        uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
+{
+    trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
+
+    /* nop */
+}
+
+static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
+        uint8_t phy_addr, uint8_t reg_addr)
+{
+    uint16_t r = s->phy_regs[reg_addr];
+
+    trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
+
+    return r;
+}
+
+static void minimac2_update_mdio(MilkymistMinimac2State *s)
+{
+    MilkymistMinimac2MdioState *m = &s->mdio;
+
+    /* detect rising clk edge */
+    if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
+        /* shift data in */
+        int bit = ((s->regs[R_MDIO] & MDIO_DO)
+                   && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
+        m->data = (m->data << 1) | bit;
+
+        /* check for sync */
+        if (m->data == 0xffffffff) {
+            m->count = 32;
+        }
+
+        if (m->count == 16) {
+            uint8_t start = (m->data >> 14) & 0x3;
+            uint8_t op = (m->data >> 12) & 0x3;
+            uint8_t ta = (m->data) & 0x3;
+
+            if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
+                m->state = MDIO_STATE_WRITING;
+            } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
+                m->state = MDIO_STATE_READING;
+            } else {
+                m->state = MDIO_STATE_IDLE;
+            }
+
+            if (m->state != MDIO_STATE_IDLE) {
+                m->phy_addr = (m->data >> 7) & 0x1f;
+                m->reg_addr = (m->data >> 2) & 0x1f;
+            }
+
+            if (m->state == MDIO_STATE_READING) {
+                m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
+                        m->reg_addr);
+            }
+        }
+
+        if (m->count < 16 && m->state == MDIO_STATE_READING) {
+            int bit = (m->data_out & 0x8000) ? 1 : 0;
+            m->data_out <<= 1;
+
+            if (bit) {
+                s->regs[R_MDIO] |= MDIO_DI;
+            } else {
+                s->regs[R_MDIO] &= ~MDIO_DI;
+            }
+        }
+
+        if (m->count == 0 && m->state) {
+            if (m->state == MDIO_STATE_WRITING) {
+                uint16_t data = m->data & 0xffff;
+                minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
+            }
+            m->state = MDIO_STATE_IDLE;
+        }
+        m->count--;
+    }
+
+    m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
+}
+
+static size_t assemble_frame(uint8_t *buf, size_t size,
+        const uint8_t *payload, size_t payload_size)
+{
+    uint32_t crc;
+
+    if (size < payload_size + 12) {
+        error_report("milkymist_minimac2: received too big ethernet frame");
+        return 0;
+    }
+
+    /* prepend preamble and sfd */
+    memcpy(buf, preamble_sfd, 8);
+
+    /* now copy the payload */
+    memcpy(buf + 8, payload, payload_size);
+
+    /* pad frame if needed */
+    if (payload_size < 60) {
+        memset(buf + payload_size + 8, 0, 60 - payload_size);
+        payload_size = 60;
+    }
+
+    /* append fcs */
+    crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
+    memcpy(buf + payload_size + 8, &crc, 4);
+
+    return payload_size + 12;
+}
+
+static void minimac2_tx(MilkymistMinimac2State *s)
+{
+    uint32_t txcount = s->regs[R_TXCOUNT];
+    uint8_t *buf = s->tx_buf;
+
+    if (txcount < 64) {
+        error_report("milkymist_minimac2: ethernet frame too small (%u < %u)\n",
+                txcount, 64);
+        goto err;
+    }
+
+    if (txcount > MINIMAC2_MTU) {
+        error_report("milkymist_minimac2: MTU exceeded (%u > %u)\n",
+                txcount, MINIMAC2_MTU);
+        goto err;
+    }
+
+    if (memcmp(buf, preamble_sfd, 8) != 0) {
+        error_report("milkymist_minimac2: frame doesn't contain the preamble "
+                "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)\n",
+                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+        goto err;
+    }
+
+    trace_milkymist_minimac2_tx_frame(txcount - 12);
+
+    /* send packet, skipping preamble and sfd */
+    qemu_send_packet_raw(&s->nic->nc, buf + 8, txcount - 12);
+
+    s->regs[R_TXCOUNT] = 0;
+
+err:
+    trace_milkymist_minimac2_pulse_irq_tx();
+    qemu_irq_pulse(s->tx_irq);
+}
+
+static void update_rx_interrupt(MilkymistMinimac2State *s)
+{
+    if (s->regs[R_STATE0] == STATE_PENDING
+            || s->regs[R_STATE1] == STATE_PENDING) {
+        trace_milkymist_minimac2_raise_irq_rx();
+        qemu_irq_raise(s->rx_irq);
+    } else {
+        trace_milkymist_minimac2_lower_irq_rx();
+        qemu_irq_lower(s->rx_irq);
+    }
+}
+
+static ssize_t minimac2_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+    MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    uint32_t r_count;
+    uint32_t r_state;
+    uint8_t *rx_buf;
+
+    size_t frame_size;
+
+    trace_milkymist_minimac2_rx_frame(buf, size);
+
+    /* choose appropriate slot */
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        r_count = R_COUNT0;
+        r_state = R_STATE0;
+        rx_buf = s->rx0_buf;
+    } else if (s->regs[R_STATE1] == STATE_LOADED) {
+        r_count = R_COUNT1;
+        r_state = R_STATE1;
+        rx_buf = s->rx1_buf;
+    } else {
+        trace_milkymist_minimac2_drop_rx_frame(buf);
+        return size;
+    }
+
+    /* assemble frame */
+    frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
+
+    if (frame_size == 0) {
+        return size;
+    }
+
+    trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
+
+    /* update slot */
+    s->regs[r_count] = frame_size;
+    s->regs[r_state] = STATE_PENDING;
+
+    update_rx_interrupt(s);
+
+    return size;
+}
+
+static uint32_t
+minimac2_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistMinimac2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SETUP:
+    case R_MDIO:
+    case R_STATE0:
+    case R_COUNT0:
+    case R_STATE1:
+    case R_COUNT1:
+    case R_TXCOUNT:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_minimac2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_minimac2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+minimac2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistMinimac2State *s = opaque;
+
+    trace_milkymist_minimac2_memory_read(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_MDIO:
+    {
+        /* MDIO_DI is read only */
+        int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
+        s->regs[R_MDIO] = value;
+        if (mdio_di) {
+            s->regs[R_MDIO] |= mdio_di;
+        } else {
+            s->regs[R_MDIO] &= ~mdio_di;
+        }
+
+        minimac2_update_mdio(s);
+    } break;
+    case R_TXCOUNT:
+        s->regs[addr] = value;
+        if (value > 0) {
+            minimac2_tx(s);
+        }
+        break;
+    case R_STATE0:
+    case R_STATE1:
+        s->regs[addr] = value;
+        update_rx_interrupt(s);
+        break;
+    case R_SETUP:
+    case R_COUNT0:
+    case R_COUNT1:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_minimac2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const minimac2_read_fn[] = {
+    NULL,
+    NULL,
+    &minimac2_read,
+};
+
+static CPUWriteMemoryFunc * const minimac2_write_fn[] = {
+    NULL,
+    NULL,
+    &minimac2_write,
+};
+
+static int minimac2_can_rx(VLANClientState *nc)
+{
+    MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        return 1;
+    }
+    if (s->regs[R_STATE1] == STATE_LOADED) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void minimac2_cleanup(VLANClientState *nc)
+{
+    MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
+static void milkymist_minimac2_reset(DeviceState *d)
+{
+    MilkymistMinimac2State *s =
+            container_of(d, MilkymistMinimac2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < R_PHY_MAX; i++) {
+        s->phy_regs[i] = 0;
+    }
+
+    /* defaults */
+    s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
+    s->phy_regs[R_PHY_ID2] = 0x161a;
+}
+
+static NetClientInfo net_milkymist_minimac2_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = minimac2_can_rx,
+    .receive = minimac2_rx,
+    .cleanup = minimac2_cleanup,
+};
+
+static int milkymist_minimac2_init(SysBusDevice *dev)
+{
+    MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev);
+    int regs;
+    ram_addr_t buffers;
+    size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
+
+    sysbus_init_irq(dev, &s->rx_irq);
+    sysbus_init_irq(dev, &s->tx_irq);
+
+    regs = cpu_register_io_memory(minimac2_read_fn, minimac2_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, regs);
+
+    /* register buffers memory */
+    buffers = qemu_ram_alloc(NULL, "milkymist_minimac2.buffers", buffers_size);
+    s->rx0_buf = qemu_get_ram_ptr(buffers);
+    s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
+    s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
+
+    cpu_register_physical_memory(s->buffers_base, buffers_size,
+            buffers | IO_MEM_RAM);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
+    .name = "milkymist-minimac2-mdio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
+        VMSTATE_INT32(count, MilkymistMinimac2MdioState),
+        VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
+        VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
+        VMSTATE_INT32(state, MilkymistMinimac2MdioState),
+        VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
+        VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_milkymist_minimac2 = {
+    .name = "milkymist-minimac2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
+        VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
+        VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
+                vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_minimac2_info = {
+    .init = milkymist_minimac2_init,
+    .qdev.name  = "milkymist-minimac2",
+    .qdev.size  = sizeof(MilkymistMinimac2State),
+    .qdev.vmsd  = &vmstate_milkymist_minimac2,
+    .qdev.reset = milkymist_minimac2_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State,
+                buffers_base, 0),
+        DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
+        DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_minimac2_register(void)
+{
+    sysbus_register_withprop(&milkymist_minimac2_info);
+}
+
+device_init(milkymist_minimac2_register)
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
new file mode 100644 (file)
index 0000000..94e6315
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ *  QEMU model of the Milkymist programmable FPU.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/pfpu.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-log.h"
+#include "qemu-error.h"
+#include <math.h>
+
+/* #define TRACE_EXEC */
+
+#ifdef TRACE_EXEC
+#    define D_EXEC(x) x
+#else
+#    define D_EXEC(x)
+#endif
+
+enum {
+    R_CTL = 0,
+    R_MESHBASE,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_CODEPAGE,
+    R_VERTICES,
+    R_COLLISIONS,
+    R_STRAYWRITES,
+    R_LASTDMA,
+    R_PC,
+    R_DREGBASE,
+    R_CODEBASE,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY = (1<<0),
+};
+
+enum {
+    OP_NOP = 0,
+    OP_FADD,
+    OP_FSUB,
+    OP_FMUL,
+    OP_FABS,
+    OP_F2I,
+    OP_I2F,
+    OP_VECTOUT,
+    OP_SIN,
+    OP_COS,
+    OP_ABOVE,
+    OP_EQUAL,
+    OP_COPY,
+    OP_IF,
+    OP_TSIGN,
+    OP_QUAKE,
+};
+
+enum {
+    GPR_X = 0,
+    GPR_Y = 1,
+    GPR_FLAGS = 2,
+};
+
+enum {
+    LATENCY_FADD = 5,
+    LATENCY_FSUB = 5,
+    LATENCY_FMUL = 7,
+    LATENCY_FABS = 2,
+    LATENCY_F2I = 2,
+    LATENCY_I2F = 3,
+    LATENCY_VECTOUT = 0,
+    LATENCY_SIN = 4,
+    LATENCY_COS = 4,
+    LATENCY_ABOVE = 2,
+    LATENCY_EQUAL = 2,
+    LATENCY_COPY = 2,
+    LATENCY_IF = 2,
+    LATENCY_TSIGN = 2,
+    LATENCY_QUAKE = 2,
+    MAX_LATENCY = 7
+};
+
+#define GPR_BEGIN       0x100
+#define GPR_END         0x17f
+#define MICROCODE_BEGIN 0x200
+#define MICROCODE_END   0x3ff
+#define MICROCODE_WORDS 2048
+
+#define REINTERPRET_CAST(type, val) (*((type *)&(val)))
+
+#ifdef TRACE_EXEC
+static const char *opcode_to_str[] = {
+    "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT",
+    "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE",
+};
+#endif
+
+struct MilkymistPFPUState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+    uint32_t gp_regs[128];
+    uint32_t microcode[MICROCODE_WORDS];
+
+    int output_queue_pos;
+    uint32_t output_queue[MAX_LATENCY];
+};
+typedef struct MilkymistPFPUState MilkymistPFPUState;
+
+static inline target_phys_addr_t
+get_dma_address(uint32_t base, uint32_t x, uint32_t y)
+{
+    return base + 8 * (128 * y + x);
+}
+
+static inline void
+output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos)
+{
+    s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val;
+}
+
+static inline uint32_t
+output_queue_remove(MilkymistPFPUState *s)
+{
+    return s->output_queue[s->output_queue_pos];
+}
+
+static inline void
+output_queue_advance(MilkymistPFPUState *s)
+{
+    s->output_queue[s->output_queue_pos] = 0;
+    s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY;
+}
+
+static int pfpu_decode_insn(MilkymistPFPUState *s)
+{
+    uint32_t pc = s->regs[R_PC];
+    uint32_t insn = s->microcode[pc];
+    uint32_t reg_a = (insn >> 18) & 0x7f;
+    uint32_t reg_b = (insn >> 11) & 0x7f;
+    uint32_t op = (insn >> 7) & 0xf;
+    uint32_t reg_d = insn & 0x7f;
+    uint32_t r = 0;
+    int latency = 0;
+
+    switch (op) {
+    case OP_NOP:
+        break;
+    case OP_FADD:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a + b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FADD;
+        D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FSUB:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a - b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FSUB;
+        D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FMUL:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a * b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FMUL;
+        D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FABS:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float t = fabsf(a);
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FABS;
+        D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_F2I:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        int32_t t = a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_F2I;
+        D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r));
+    } break;
+    case OP_I2F:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_I2F;
+        D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_VECTOUT:
+    {
+        uint32_t a = cpu_to_be32(s->gp_regs[reg_a]);
+        uint32_t b = cpu_to_be32(s->gp_regs[reg_b]);
+        target_phys_addr_t dma_ptr =
+            get_dma_address(s->regs[R_MESHBASE],
+                    s->gp_regs[GPR_X], s->gp_regs[GPR_Y]);
+        cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4);
+        cpu_physical_memory_write(dma_ptr + 4, (uint8_t *)&b, 4);
+        s->regs[R_LASTDMA] = dma_ptr + 4;
+        D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr));
+        trace_milkymist_pfpu_vectout(a, b, dma_ptr);
+    } break;
+    case OP_SIN:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = sinf(a * (1.0f / (M_PI * 4096.0f)));
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_SIN;
+        D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_COS:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = cosf(a * (1.0f / (M_PI * 4096.0f)));
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_COS;
+        D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_ABOVE:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (a > b) ? 1.0f : 0.0f;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_ABOVE;
+        D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_EQUAL:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (a == b) ? 1.0f : 0.0f;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_EQUAL;
+        D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_COPY:
+    {
+        r = s->gp_regs[reg_a];
+        latency = LATENCY_COPY;
+        D_EXEC(qemu_log("COPY"));
+    } break;
+    case OP_IF:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        uint32_t f = s->gp_regs[GPR_FLAGS];
+        float t = (f != 0) ? a : b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_IF;
+        D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r));
+    } break;
+    case OP_TSIGN:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (b < 0) ? -a : a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_TSIGN;
+        D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_QUAKE:
+    {
+        uint32_t a = s->gp_regs[reg_a];
+        r = 0x5f3759df - (a >> 1);
+        latency = LATENCY_QUAKE;
+        D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r));
+    } break;
+
+    default:
+        error_report("milkymist_pfpu: unknown opcode %d\n", op);
+        break;
+    }
+
+    if (!reg_d) {
+        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n",
+                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
+                    s->regs[R_PC] + latency));
+    } else {
+        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n",
+                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
+                    s->regs[R_PC] + latency, reg_d));
+    }
+
+    if (op == OP_VECTOUT) {
+        return 0;
+    }
+
+    /* store output for this cycle */
+    if (reg_d) {
+        uint32_t val = output_queue_remove(s);
+        D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val));
+        s->gp_regs[reg_d] = val;
+    }
+
+    output_queue_advance(s);
+
+    /* store op output */
+    if (op != OP_NOP) {
+        output_queue_insert(s, r, latency-1);
+    }
+
+    /* advance PC */
+    s->regs[R_PC]++;
+
+    return 1;
+};
+
+static void pfpu_start(MilkymistPFPUState *s)
+{
+    int x, y;
+    int i;
+
+    for (y = 0; y <= s->regs[R_VMESHLAST]; y++) {
+        for (x = 0; x <= s->regs[R_HMESHLAST]; x++) {
+            D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y));
+
+            /* set current position */
+            s->gp_regs[GPR_X] = x;
+            s->gp_regs[GPR_Y] = y;
+
+            /* run microcode on this position */
+            i = 0;
+            while (pfpu_decode_insn(s)) {
+                /* decode at most MICROCODE_WORDS instructions */
+                if (i++ >= MICROCODE_WORDS) {
+                    error_report("milkymist_pfpu: too many instructions "
+                            "executed in microcode. No VECTOUT?\n");
+                    break;
+                }
+            }
+
+            /* reset pc for next run */
+            s->regs[R_PC] = 0;
+        }
+    }
+
+    s->regs[R_VERTICES] = x * y;
+
+    trace_milkymist_pfpu_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
+{
+    return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
+}
+
+static uint32_t pfpu_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistPFPUState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_MESHBASE:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CODEPAGE:
+    case R_VERTICES:
+    case R_COLLISIONS:
+    case R_STRAYWRITES:
+    case R_LASTDMA:
+    case R_PC:
+    case R_DREGBASE:
+    case R_CODEBASE:
+        r = s->regs[addr];
+        break;
+    case GPR_BEGIN ... GPR_END:
+        r = s->gp_regs[addr - GPR_BEGIN];
+        break;
+    case MICROCODE_BEGIN ...  MICROCODE_END:
+        r = s->microcode[get_microcode_address(s, addr)];
+        break;
+
+    default:
+        error_report("milkymist_pfpu: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_pfpu_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+pfpu_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistPFPUState *s = opaque;
+
+    trace_milkymist_pfpu_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        if (value & CTL_START_BUSY) {
+            pfpu_start(s);
+        }
+        break;
+    case R_MESHBASE:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CODEPAGE:
+    case R_VERTICES:
+    case R_COLLISIONS:
+    case R_STRAYWRITES:
+    case R_LASTDMA:
+    case R_PC:
+    case R_DREGBASE:
+    case R_CODEBASE:
+        s->regs[addr] = value;
+        break;
+    case GPR_BEGIN ...  GPR_END:
+        s->gp_regs[addr - GPR_BEGIN] = value;
+        break;
+    case MICROCODE_BEGIN ...  MICROCODE_END:
+        s->microcode[get_microcode_address(s, addr)] = value;
+        break;
+
+    default:
+        error_report("milkymist_pfpu: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const pfpu_read_fn[] = {
+    NULL,
+    NULL,
+    &pfpu_read,
+};
+
+static CPUWriteMemoryFunc * const pfpu_write_fn[] = {
+    NULL,
+    NULL,
+    &pfpu_write,
+};
+
+static void milkymist_pfpu_reset(DeviceState *d)
+{
+    MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < 128; i++) {
+        s->gp_regs[i] = 0;
+    }
+    for (i = 0; i < MICROCODE_WORDS; i++) {
+        s->microcode[i] = 0;
+    }
+    s->output_queue_pos = 0;
+    for (i = 0; i < MAX_LATENCY; i++) {
+        s->output_queue[i] = 0;
+    }
+}
+
+static int milkymist_pfpu_init(SysBusDevice *dev)
+{
+    MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev);
+    int pfpu_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    pfpu_regs = cpu_register_io_memory(pfpu_read_fn, pfpu_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, MICROCODE_END * 4, pfpu_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_pfpu = {
+    .name = "milkymist-pfpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX),
+        VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128),
+        VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS),
+        VMSTATE_INT32(output_queue_pos, MilkymistPFPUState),
+        VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_pfpu_info = {
+    .init = milkymist_pfpu_init,
+    .qdev.name  = "milkymist-pfpu",
+    .qdev.size  = sizeof(MilkymistPFPUState),
+    .qdev.vmsd  = &vmstate_milkymist_pfpu,
+    .qdev.reset = milkymist_pfpu_reset,
+};
+
+static void milkymist_pfpu_register(void)
+{
+    sysbus_register_withprop(&milkymist_pfpu_info);
+}
+
+device_init(milkymist_pfpu_register)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
new file mode 100644 (file)
index 0000000..1565260
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ *  QEMU model of the Milkymist SoftUSB block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "console.h"
+#include "usb.h"
+#include "qemu-error.h"
+
+enum {
+    R_CTRL = 0,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+#define COMLOC_DEBUG_PRODUCE 0x1000
+#define COMLOC_DEBUG_BASE    0x1001
+#define COMLOC_MEVT_PRODUCE  0x1101
+#define COMLOC_MEVT_BASE     0x1102
+#define COMLOC_KEVT_PRODUCE  0x1142
+#define COMLOC_KEVT_BASE     0x1143
+
+struct MilkymistSoftUsbState {
+    SysBusDevice busdev;
+    USBBus usbbus;
+    USBPort usbport[2];
+    USBDevice *usbdev;
+
+    qemu_irq irq;
+
+    /* device properties */
+    uint32_t pmem_base;
+    uint32_t pmem_size;
+    uint32_t dmem_base;
+    uint32_t dmem_size;
+
+    /* device registers */
+    uint32_t regs[R_MAX];
+
+    /* mouse state */
+    int mouse_dx;
+    int mouse_dy;
+    int mouse_dz;
+    uint8_t mouse_buttons_state;
+
+    /* keyboard state */
+    uint8_t kbd_usb_buffer[8];
+};
+typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
+
+static uint32_t softusb_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistSoftUsbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_softusb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_softusb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+softusb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    trace_milkymist_softusb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_softusb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const softusb_read_fn[] = {
+    NULL,
+    NULL,
+    &softusb_read,
+};
+
+static CPUWriteMemoryFunc * const softusb_write_fn[] = {
+    NULL,
+    NULL,
+    &softusb_write,
+};
+
+static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: read dmem out of bounds "
+                "at offset 0x%x, len %d\n", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_read(s->dmem_base + offset, buf, len);
+}
+
+static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: write dmem out of bounds "
+                "at offset 0x%x, len %d\n", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_write(s->dmem_base + offset, buf, len);
+}
+
+static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: read pmem out of bounds "
+                "at offset 0x%x, len %d\n", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_read(s->pmem_base + offset, buf, len);
+}
+
+static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: write pmem out of bounds "
+                "at offset 0x%x, len %d\n", offset, len);
+        return;
+    }
+
+    cpu_physical_memory_write(s->pmem_base + offset, buf, len);
+}
+
+static void softusb_mouse_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+    uint8_t buf[4];
+
+    buf[0] = s->mouse_buttons_state;
+    buf[1] = s->mouse_dx;
+    buf[2] = s->mouse_dy;
+    buf[3] = s->mouse_dz;
+
+    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_mevt(m);
+    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, buf, 4);
+    m = (m + 1) & 0xf;
+    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_kbd_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+
+    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_kevt(m);
+    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_usb_buffer, 8);
+    m = (m + 1) & 0x7;
+    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_mouse_event(void *opaque,
+       int dx, int dy, int dz, int buttons_state)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    trace_milkymist_softusb_mouse_event(dx, dy, dz, buttons_state);
+
+    s->mouse_dx = dx;
+    s->mouse_dy = dy;
+    s->mouse_dz = dz;
+    s->mouse_buttons_state = buttons_state;
+
+    softusb_mouse_changed(s);
+}
+
+static void softusb_usbdev_datain(void *opaque)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    USBPacket p;
+
+    p.pid = USB_TOKEN_IN;
+    p.devep = 1;
+    p.data = s->kbd_usb_buffer;
+    p.len = sizeof(s->kbd_usb_buffer);
+    s->usbdev->info->handle_data(s->usbdev, &p);
+
+    softusb_kbd_changed(s);
+}
+
+static void softusb_attach(USBPort *port)
+{
+}
+
+static USBPortOps softusb_ops = {
+    .attach = softusb_attach,
+};
+
+static void milkymist_softusb_reset(DeviceState *d)
+{
+    MilkymistSoftUsbState *s =
+            container_of(d, MilkymistSoftUsbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    s->mouse_dx = 0;
+    s->mouse_dy = 0;
+    s->mouse_dz = 0;
+    s->mouse_buttons_state = 0;
+    memset(s->kbd_usb_buffer, 0, sizeof(s->kbd_usb_buffer));
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+}
+
+static int milkymist_softusb_init(SysBusDevice *dev)
+{
+    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
+    int softusb_regs;
+    ram_addr_t pmem_ram;
+    ram_addr_t dmem_ram;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    softusb_regs = cpu_register_io_memory(softusb_read_fn, softusb_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, softusb_regs);
+
+    /* register pmem and dmem */
+    pmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.pmem", s->pmem_size);
+    cpu_register_physical_memory(s->pmem_base, s->pmem_size,
+            pmem_ram | IO_MEM_RAM);
+    dmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.dmem", s->dmem_size);
+    cpu_register_physical_memory(s->dmem_base, s->dmem_size,
+            dmem_ram | IO_MEM_RAM);
+
+    qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse");
+
+    /* create our usb bus */
+    usb_bus_new(&s->usbbus, NULL);
+
+    /* our two ports */
+    usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
+            USB_SPEED_MASK_LOW);
+    usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
+            USB_SPEED_MASK_LOW);
+
+    /* and finally create an usb keyboard */
+    s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");
+    usb_hid_datain_cb(s->usbdev, s, softusb_usbdev_datain);
+    s->usbdev->info->handle_reset(s->usbdev);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_softusb = {
+    .name = "milkymist-softusb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
+        VMSTATE_INT32(mouse_dx, MilkymistSoftUsbState),
+        VMSTATE_INT32(mouse_dy, MilkymistSoftUsbState),
+        VMSTATE_INT32(mouse_dz, MilkymistSoftUsbState),
+        VMSTATE_UINT8(mouse_buttons_state, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(kbd_usb_buffer, MilkymistSoftUsbState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_softusb_info = {
+    .init = milkymist_softusb_init,
+    .qdev.name  = "milkymist-softusb",
+    .qdev.size  = sizeof(MilkymistSoftUsbState),
+    .qdev.vmsd  = &vmstate_milkymist_softusb,
+    .qdev.reset = milkymist_softusb_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32(
+                "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
+        ),
+        DEFINE_PROP_UINT32(
+                "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
+        ),
+        DEFINE_PROP_UINT32(
+                "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
+        ),
+        DEFINE_PROP_UINT32(
+                "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
+        ),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_softusb_register(void)
+{
+    sysbus_register_withprop(&milkymist_softusb_info);
+}
+
+device_init(milkymist_softusb_register)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
new file mode 100644 (file)
index 0000000..6bd0cb9
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/sysctl.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu-timer.h"
+#include "qemu-error.h"
+
+enum {
+    CTRL_ENABLE      = (1<<0),
+    CTRL_AUTORESTART = (1<<1),
+};
+
+enum {
+    ICAP_READY       = (1<<0),
+};
+
+enum {
+    R_GPIO_IN = 0,
+    R_GPIO_OUT,
+    R_GPIO_INTEN,
+    R_RESERVED0,
+    R_TIMER0_CONTROL,
+    R_TIMER0_COMPARE,
+    R_TIMER0_COUNTER,
+    R_RESERVED1,
+    R_TIMER1_CONTROL,
+    R_TIMER1_COMPARE,
+    R_TIMER1_COUNTER,
+    R_RESERVED2,
+    R_RESERVED3,
+    R_ICAP,
+    R_CAPABILITIES,
+    R_SYSTEM_ID,
+    R_MAX
+};
+
+struct MilkymistSysctlState {
+    SysBusDevice busdev;
+
+    QEMUBH *bh0;
+    QEMUBH *bh1;
+    ptimer_state *ptimer0;
+    ptimer_state *ptimer1;
+
+    uint32_t freq_hz;
+    uint32_t capabilities;
+    uint32_t systemid;
+    uint32_t strappings;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq gpio_irq;
+    qemu_irq timer0_irq;
+    qemu_irq timer1_irq;
+};
+typedef struct MilkymistSysctlState MilkymistSysctlState;
+
+static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
+{
+    trace_milkymist_sysctl_icap_write(value);
+    switch (value & 0xffff) {
+    case 0x000e:
+        qemu_system_shutdown_request();
+        break;
+    }
+}
+
+static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistSysctlState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_TIMER0_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer0);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER0_COMPARE] - r;
+        break;
+    case R_TIMER1_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer1);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER1_COMPARE] - r;
+        break;
+    case R_GPIO_IN:
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_CONTROL:
+    case R_TIMER0_COMPARE:
+    case R_TIMER1_CONTROL:
+    case R_TIMER1_COMPARE:
+    case R_ICAP:
+    case R_CAPABILITIES:
+    case R_SYSTEM_ID:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_sysctl: read access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_sysctl_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistSysctlState *s = opaque;
+
+    trace_milkymist_sysctl_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_COUNTER:
+    case R_TIMER1_COUNTER:
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_COMPARE:
+        ptimer_set_limit(s->ptimer0, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER1_COMPARE:
+        ptimer_set_limit(s->ptimer1, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer0();
+            ptimer_set_count(s->ptimer0,
+                    s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
+            ptimer_run(s->ptimer0, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer0();
+            ptimer_stop(s->ptimer0);
+        }
+        break;
+    case R_TIMER1_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer1();
+            ptimer_set_count(s->ptimer1,
+                    s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
+            ptimer_run(s->ptimer1, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer1();
+            ptimer_stop(s->ptimer1);
+        }
+        break;
+    case R_ICAP:
+        sysctl_icap_write(s, value);
+        break;
+    case R_SYSTEM_ID:
+        qemu_system_reset_request();
+        break;
+
+    case R_GPIO_IN:
+    case R_CAPABILITIES:
+        error_report("milkymist_sysctl: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_sysctl: write access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const sysctl_read_fn[] = {
+    NULL,
+    NULL,
+    &sysctl_read,
+};
+
+static CPUWriteMemoryFunc * const sysctl_write_fn[] = {
+    NULL,
+    NULL,
+    &sysctl_write,
+};
+
+static void timer0_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer0();
+        ptimer_stop(s->ptimer0);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer0();
+    qemu_irq_pulse(s->timer0_irq);
+}
+
+static void timer1_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer1();
+        ptimer_stop(s->ptimer1);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer1();
+    qemu_irq_pulse(s->timer1_irq);
+}
+
+static void milkymist_sysctl_reset(DeviceState *d)
+{
+    MilkymistSysctlState *s =
+            container_of(d, MilkymistSysctlState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    ptimer_stop(s->ptimer0);
+    ptimer_stop(s->ptimer1);
+
+    /* defaults */
+    s->regs[R_ICAP] = ICAP_READY;
+    s->regs[R_SYSTEM_ID] = s->systemid;
+    s->regs[R_CAPABILITIES] = s->capabilities;
+    s->regs[R_GPIO_IN] = s->strappings;
+}
+
+static int milkymist_sysctl_init(SysBusDevice *dev)
+{
+    MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
+    int sysctl_regs;
+
+    sysbus_init_irq(dev, &s->gpio_irq);
+    sysbus_init_irq(dev, &s->timer0_irq);
+    sysbus_init_irq(dev, &s->timer1_irq);
+
+    s->bh0 = qemu_bh_new(timer0_hit, s);
+    s->bh1 = qemu_bh_new(timer1_hit, s);
+    s->ptimer0 = ptimer_init(s->bh0);
+    s->ptimer1 = ptimer_init(s->bh1);
+    ptimer_set_freq(s->ptimer0, s->freq_hz);
+    ptimer_set_freq(s->ptimer1, s->freq_hz);
+
+    sysctl_regs = cpu_register_io_memory(sysctl_read_fn, sysctl_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, sysctl_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_sysctl = {
+    .name = "milkymist-sysctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
+        VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
+        VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_sysctl_info = {
+    .init = milkymist_sysctl_init,
+    .qdev.name  = "milkymist-sysctl",
+    .qdev.size  = sizeof(MilkymistSysctlState),
+    .qdev.vmsd  = &vmstate_milkymist_sysctl,
+    .qdev.reset = milkymist_sysctl_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
+                freq_hz, 80000000),
+        DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
+                capabilities, 0x00000000),
+        DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
+                systemid, 0x10014d31),
+        DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
+                strappings, 0x00000001),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_sysctl_register(void)
+{
+    sysbus_register_withprop(&milkymist_sysctl_info);
+}
+
+device_init(milkymist_sysctl_register)
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
new file mode 100644 (file)
index 0000000..9cebe31
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ *  QEMU model of the Milkymist texture mapping unit.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *  Copyright (c) 2010 Sebastien Bourdeauducq
+ *                       <sebastien.bourdeauducq@lekernel.net>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/tmu2.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-error.h"
+
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+enum {
+    R_CTL = 0,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_BRIGHTNESS,
+    R_CHROMAKEY,
+    R_VERTICESADDR,
+    R_TEXFBUF,
+    R_TEXHRES,
+    R_TEXVRES,
+    R_TEXHMASK,
+    R_TEXVMASK,
+    R_DSTFBUF,
+    R_DSTHRES,
+    R_DSTVRES,
+    R_DSTHOFFSET,
+    R_DSTVOFFSET,
+    R_DSTSQUAREW,
+    R_DSTSQUAREH,
+    R_ALPHA,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY  = (1<<0),
+    CTL_CHROMAKEY   = (1<<1),
+};
+
+enum {
+    MAX_BRIGHTNESS = 63,
+    MAX_ALPHA      = 63,
+};
+
+enum {
+    MESH_MAXSIZE = 128,
+};
+
+struct vertex {
+    int x;
+    int y;
+} __attribute__((packed));
+
+struct MilkymistTMU2State {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+
+    Display *dpy;
+    GLXFBConfig glx_fb_config;
+    GLXContext glx_context;
+};
+typedef struct MilkymistTMU2State MilkymistTMU2State;
+
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+
+static int tmu2_glx_init(MilkymistTMU2State *s)
+{
+    GLXFBConfig *configs;
+    int nelements;
+
+    s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
+    if (s->dpy == NULL) {
+        return 1;
+    }
+
+    configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        return 1;
+    }
+
+    s->glx_fb_config = *configs;
+    XFree(configs);
+
+    /* FIXME: call glXDestroyContext() */
+    s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
+            GLX_RGBA_TYPE, NULL, 1);
+    if (s->glx_context == NULL) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
+        int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
+{
+    int x, y;
+    int x0, y0, x1, y1;
+    int u0, v0, u1, v1, u2, v2, u3, v3;
+    double xscale = 1.0 / ((double)(64 * texhres));
+    double yscale = 1.0 / ((double)(64 * texvres));
+
+    glLoadIdentity();
+    glTranslatef(ho, vo, 0);
+    glEnable(GL_TEXTURE_2D);
+    glBegin(GL_QUADS);
+
+    for (y = 0; y < vmeshlast; y++) {
+        y0 = y * sh;
+        y1 = y0 + sh;
+        for (x = 0; x < hmeshlast; x++) {
+            x0 = x * sw;
+            x1 = x0 + sw;
+
+            u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
+            v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
+            u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
+            v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
+            u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
+            v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
+            u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
+            v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
+
+            glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
+            glVertex3i(x0, y0, 0);
+            glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
+            glVertex3i(x1, y0, 0);
+            glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
+            glVertex3i(x1, y1, 0);
+            glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
+            glVertex3i(x0, y1, 0);
+        }
+    }
+
+    glEnd();
+}
+
+static void tmu2_start(MilkymistTMU2State *s)
+{
+    int pbuffer_attrib[6] = {
+        GLX_PBUFFER_WIDTH,
+        0,
+        GLX_PBUFFER_HEIGHT,
+        0,
+        GLX_PRESERVED_CONTENTS,
+        True
+    };
+
+    GLXPbuffer pbuffer;
+    GLuint texture;
+    void *fb;
+    target_phys_addr_t fb_len;
+    void *mesh;
+    target_phys_addr_t mesh_len;
+    float m;
+
+    trace_milkymist_tmu2_start();
+
+    /* Create and set up a suitable OpenGL context */
+    pbuffer_attrib[1] = s->regs[R_DSTHRES];
+    pbuffer_attrib[3] = s->regs[R_DSTVRES];
+    pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
+    glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
+
+    /* Fixup endianness. TODO: would it work on BE hosts? */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+    glPixelStorei(GL_PACK_SWAP_BYTES, 1);
+
+    /* Row alignment */
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_PACK_ALIGNMENT, 2);
+
+    /* Read the QEMU source framebuffer into an OpenGL texture */
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES];
+    fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+    glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+            0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+
+    /* Set up texturing options */
+    /* WARNING:
+     * Many cases of TMU2 masking are not supported by OpenGL.
+     * We only implement the most common ones:
+     *  - full bilinear filtering vs. nearest texel
+     *  - texture clamping vs. texture wrapping
+     */
+    if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    }
+    if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    }
+    if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    }
+
+    /* Translucency and decay */
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
+    glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
+
+    /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+    glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+
+    /* Map the texture */
+    mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
+    mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0);
+    if (mesh == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    tmu2_gl_map((struct vertex *)mesh,
+        s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+        s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
+        s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
+        s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
+    cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
+
+    /* Write back the OpenGL framebuffer to the QEMU framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
+
+    /* Free OpenGL allocs */
+    glDeleteTextures(1, &texture);
+    glXMakeContextCurrent(s->dpy, None, None, NULL);
+    glXDestroyPbuffer(s->dpy, pbuffer);
+
+    s->regs[R_CTL] &= ~CTL_START_BUSY;
+
+    trace_milkymist_tmu2_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static uint32_t tmu2_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistTMU2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_BRIGHTNESS:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_tmu2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_tmu2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void tmu2_check_registers(MilkymistTMU2State *s)
+{
+    if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
+        error_report("milkymist_tmu2: max brightness is %d\n", MAX_BRIGHTNESS);
+    }
+
+    if (s->regs[R_ALPHA] > MAX_ALPHA) {
+        error_report("milkymist_tmu2: max alpha is %d\n", MAX_ALPHA);
+    }
+
+    if (s->regs[R_VERTICESADDR] & 0x07) {
+        error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
+                "aligned\n");
+    }
+
+    if (s->regs[R_TEXFBUF] & 0x01) {
+        error_report("milkymist_tmu2: texture buffer address has to be "
+                "16-bit aligned\n");
+    }
+}
+
+static void tmu2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistTMU2State *s = opaque;
+
+    trace_milkymist_tmu2_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        s->regs[addr] = value;
+        if (value & CTL_START_BUSY) {
+            tmu2_start(s);
+        }
+        break;
+    case R_BRIGHTNESS:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_tmu2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    tmu2_check_registers(s);
+}
+
+static CPUReadMemoryFunc * const tmu2_read_fn[] = {
+    NULL,
+    NULL,
+    &tmu2_read,
+};
+
+static CPUWriteMemoryFunc * const tmu2_write_fn[] = {
+    NULL,
+    NULL,
+    &tmu2_write,
+};
+
+static void milkymist_tmu2_reset(DeviceState *d)
+{
+    MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_tmu2_init(SysBusDevice *dev)
+{
+    MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev);
+    int tmu2_regs;
+
+    if (tmu2_glx_init(s)) {
+        return 1;
+    }
+
+    sysbus_init_irq(dev, &s->irq);
+
+    tmu2_regs = cpu_register_io_memory(tmu2_read_fn, tmu2_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, tmu2_regs);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_tmu2 = {
+    .name = "milkymist-tmu2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_tmu2_info = {
+    .init = milkymist_tmu2_init,
+    .qdev.name  = "milkymist-tmu2",
+    .qdev.size  = sizeof(MilkymistTMU2State),
+    .qdev.vmsd  = &vmstate_milkymist_tmu2,
+    .qdev.reset = milkymist_tmu2_reset,
+};
+
+static void milkymist_tmu2_register(void)
+{
+    sysbus_register_withprop(&milkymist_tmu2_info);
+}
+
+device_init(milkymist_tmu2_register)
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
new file mode 100644 (file)
index 0000000..56c90da
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  QEMU model of the Milkymist UART block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/uart.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+#include "qemu-error.h"
+
+enum {
+    R_RXTX = 0,
+    R_DIV,
+    R_MAX
+};
+
+struct MilkymistUartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq rx_irq;
+    qemu_irq tx_irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistUartState MilkymistUartState;
+
+static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistUartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+    case R_DIV:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_uart: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_uart_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistUartState *s = opaque;
+    unsigned char ch = value;
+
+    trace_milkymist_uart_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        if (s->chr) {
+            qemu_chr_write(s->chr, &ch, 1);
+        }
+        trace_milkymist_uart_pulse_irq_tx();
+        qemu_irq_pulse(s->tx_irq);
+        break;
+    case R_DIV:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_uart: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const uart_read_fn[] = {
+    NULL,
+    NULL,
+    &uart_read,
+};
+
+static CPUWriteMemoryFunc * const uart_write_fn[] = {
+    NULL,
+    NULL,
+    &uart_write,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    MilkymistUartState *s = opaque;
+
+    s->regs[R_RXTX] = *buf;
+    trace_milkymist_uart_pulse_irq_rx();
+    qemu_irq_pulse(s->rx_irq);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    return 1;
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void milkymist_uart_reset(DeviceState *d)
+{
+    MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_uart_init(SysBusDevice *dev)
+{
+    MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
+    int uart_regs;
+
+    sysbus_init_irq(dev, &s->rx_irq);
+    sysbus_init_irq(dev, &s->tx_irq);
+
+    uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_uart = {
+    .name = "milkymist-uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_uart_info = {
+    .init = milkymist_uart_init,
+    .qdev.name  = "milkymist-uart",
+    .qdev.size  = sizeof(MilkymistUartState),
+    .qdev.vmsd  = &vmstate_milkymist_uart,
+    .qdev.reset = milkymist_uart_reset,
+};
+
+static void milkymist_uart_register(void)
+{
+    sysbus_register_withprop(&milkymist_uart_info);
+}
+
+device_init(milkymist_uart_register)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
new file mode 100644 (file)
index 0000000..2e55e42
--- /dev/null
@@ -0,0 +1,321 @@
+
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/vgafb.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "console.h"
+#include "framebuffer.h"
+#include "pixel_ops.h"
+#include "qemu-error.h"
+
+#define BITS 8
+#include "milkymist-vgafb_template.h"
+#define BITS 15
+#include "milkymist-vgafb_template.h"
+#define BITS 16
+#include "milkymist-vgafb_template.h"
+#define BITS 24
+#include "milkymist-vgafb_template.h"
+#define BITS 32
+#include "milkymist-vgafb_template.h"
+
+enum {
+    R_CTRL = 0,
+    R_HRES,
+    R_HSYNC_START,
+    R_HSYNC_END,
+    R_HSCAN,
+    R_VRES,
+    R_VSYNC_START,
+    R_VSYNC_END,
+    R_VSCAN,
+    R_BASEADDRESS,
+    R_BASEADDRESS_ACT,
+    R_BURST_COUNT,
+    R_SOURCE_CLOCK,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+struct MilkymistVgafbState {
+    SysBusDevice busdev;
+    DisplayState *ds;
+
+    int invalidate;
+    uint32_t fb_offset;
+    uint32_t fb_mask;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistVgafbState MilkymistVgafbState;
+
+static int vgafb_enabled(MilkymistVgafbState *s)
+{
+    return !(s->regs[R_CTRL] & CTRL_RESET);
+}
+
+static void vgafb_update_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    int first = 0;
+    int last = 0;
+    drawfn fn;
+
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    int dest_width = s->regs[R_HRES];
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        return;
+    case 8:
+        fn = draw_line_8;
+        break;
+    case 15:
+        fn = draw_line_15;
+        dest_width *= 2;
+        break;
+    case 16:
+        fn = draw_line_16;
+        dest_width *= 2;
+        break;
+    case 24:
+        fn = draw_line_24;
+        dest_width *= 3;
+        break;
+    case 32:
+        fn = draw_line_32;
+        dest_width *= 4;
+        break;
+    default:
+        hw_error("milkymist_vgafb: bad color depth\n");
+        break;
+    }
+
+    framebuffer_update_display(s->ds,
+                               s->regs[R_BASEADDRESS] + s->fb_offset,
+                               s->regs[R_HRES],
+                               s->regs[R_VRES],
+                               s->regs[R_HRES] * 2,
+                               dest_width,
+                               0,
+                               s->invalidate,
+                               fn,
+                               NULL,
+                               &first, &last);
+
+    if (first >= 0) {
+        dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1);
+    }
+    s->invalidate = 0;
+}
+
+static void vgafb_invalidate_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    s->invalidate = 1;
+}
+
+static void vgafb_resize(MilkymistVgafbState *s)
+{
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    qemu_console_resize(s->ds, s->regs[R_HRES], s->regs[R_VRES]);
+    s->invalidate = 1;
+}
+
+static uint32_t vgafb_read(void *opaque, target_phys_addr_t addr)
+{
+    MilkymistVgafbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+    case R_HRES:
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VRES:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BASEADDRESS:
+    case R_BURST_COUNT:
+    case R_SOURCE_CLOCK:
+        r = s->regs[addr];
+    break;
+    case R_BASEADDRESS_ACT:
+        r = s->regs[R_BASEADDRESS];
+    break;
+
+    default:
+        error_report("milkymist_vgafb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_vgafb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+vgafb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    MilkymistVgafbState *s = opaque;
+
+    trace_milkymist_vgafb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BURST_COUNT:
+    case R_SOURCE_CLOCK:
+        s->regs[addr] = value;
+        break;
+    case R_BASEADDRESS:
+        if (value & 0x1f) {
+            error_report("milkymist_vgafb: framebuffer base address have to "
+                     "be 32 byte aligned");
+            break;
+        }
+        s->regs[addr] = value & s->fb_mask;
+        s->invalidate = 1;
+        break;
+    case R_HRES:
+    case R_VRES:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_BASEADDRESS_ACT:
+        error_report("milkymist_vgafb: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_vgafb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const vgafb_read_fn[] = {
+   NULL,
+   NULL,
+   &vgafb_read
+};
+
+static CPUWriteMemoryFunc * const vgafb_write_fn[] = {
+   NULL,
+   NULL,
+   &vgafb_write
+};
+
+static void milkymist_vgafb_reset(DeviceState *d)
+{
+    MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+    s->regs[R_HRES] = 640;
+    s->regs[R_VRES] = 480;
+    s->regs[R_BASEADDRESS] = 0;
+}
+
+static int milkymist_vgafb_init(SysBusDevice *dev)
+{
+    MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
+    int vgafb_regs;
+
+    vgafb_regs = cpu_register_io_memory(vgafb_read_fn, vgafb_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, vgafb_regs);
+
+    s->ds = graphic_console_init(vgafb_update_display,
+                                 vgafb_invalidate_display,
+                                 NULL, NULL, s);
+
+    return 0;
+}
+
+static int vgafb_post_load(void *opaque, int version_id)
+{
+    vgafb_invalidate_display(opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_vgafb = {
+    .name = "milkymist-vgafb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vgafb_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo milkymist_vgafb_info = {
+    .init = milkymist_vgafb_init,
+    .qdev.name  = "milkymist-vgafb",
+    .qdev.size  = sizeof(MilkymistVgafbState),
+    .qdev.vmsd  = &vmstate_milkymist_vgafb,
+    .qdev.reset = milkymist_vgafb_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
+        DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void milkymist_vgafb_register(void)
+{
+    sysbus_register_withprop(&milkymist_vgafb_info);
+}
+
+device_init(milkymist_vgafb_register)
diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h
new file mode 100644 (file)
index 0000000..69af9ef
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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/>.
+ *
+ */
+
+#if BITS == 8
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *to = rgb_to_pixel8(r, g, b);              \
+        to += 1;                                   \
+    } while (0)
+#elif BITS == 15
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint16_t *)to = rgb_to_pixel15(r, g, b); \
+        to += 2;                                   \
+    } while (0)
+#elif BITS == 16
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint16_t *)to = rgb_to_pixel16(r, g, b); \
+        to += 2;                                   \
+    } while (0)
+#elif BITS == 24
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        uint32 tmp = rgb_to_pixel24(r, g, b);      \
+        *(to++) =         tmp & 0xff;              \
+        *(to++) =  (tmp >> 8) & 0xff;              \
+        *(to++) = (tmp >> 16) & 0xff;              \
+    } while (0)
+#elif BITS == 32
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint32_t *)to = rgb_to_pixel32(r, g, b); \
+        to += 4;                                   \
+    } while (0)
+#else
+#error unknown bit depth
+#endif
+
+static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
+        int width, int deststep)
+{
+    uint16_t rgb565;
+    uint8_t r, g, b;
+
+    while (width--) {
+        rgb565 = lduw_raw(s);
+        r = ((rgb565 >> 11) & 0x1f) << 3;
+        g = ((rgb565 >>  5) & 0x3f) << 2;
+        b = ((rgb565 >>  0) & 0x1f) << 3;
+        COPY_PIXEL(d, r, g, b);
+        s += 2;
+    }
+}
+
+#undef BITS
+#undef COPY_PIXEL
diff --git a/hw/milkymist.c b/hw/milkymist.c
new file mode 100644 (file)
index 0000000..7879840
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ *  QEMU model for the Milkymist board.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@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 "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "blockdev.h"
+#include "milkymist-hw.h"
+#include "lm32.h"
+
+#define BIOS_FILENAME    "mmone-bios.bin"
+#define BIOS_OFFSET      0x00860000
+#define BIOS_SIZE        (512*1024)
+#define KERNEL_LOAD_ADDR 0x40000000
+
+typedef struct {
+    CPUState *env;
+    target_phys_addr_t bootstrap_pc;
+    target_phys_addr_t flash_base;
+    target_phys_addr_t initrd_base;
+    size_t initrd_size;
+    target_phys_addr_t cmdline_base;
+} ResetInfo;
+
+static void cpu_irq_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = opaque;
+
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetInfo *reset_info = opaque;
+    CPUState *env = reset_info->env;
+
+    cpu_reset(env);
+
+    /* init defaults */
+    env->pc = reset_info->bootstrap_pc;
+    env->regs[R_R1] = reset_info->cmdline_base;
+    env->regs[R_R2] = reset_info->initrd_base;
+    env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size;
+    env->eba = reset_info->flash_base;
+    env->deba = reset_info->flash_base;
+}
+
+static void
+milkymist_init(ram_addr_t ram_size_not_used,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    int kernel_size;
+    DriveInfo *dinfo;
+    ram_addr_t phys_sdram;
+    ram_addr_t phys_flash;
+    qemu_irq irq[32], *cpu_irq;
+    int i;
+    char *bios_filename;
+    ResetInfo *reset_info;
+
+    /* memory map */
+    target_phys_addr_t flash_base   = 0x00000000;
+    size_t flash_sector_size        = 128 * 1024;
+    size_t flash_size               = 32 * 1024 * 1024;
+    target_phys_addr_t sdram_base   = 0x40000000;
+    size_t sdram_size               = 128 * 1024 * 1024;
+
+    target_phys_addr_t initrd_base  = sdram_base + 0x1002000;
+    target_phys_addr_t cmdline_base = sdram_base + 0x1000000;
+    size_t initrd_max = sdram_size - 0x1002000;
+
+    reset_info = qemu_mallocz(sizeof(ResetInfo));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    cpu_lm32_set_phys_msb_ignore(env, 1);
+
+    phys_sdram = qemu_ram_alloc(NULL, "milkymist.sdram", sdram_size);
+    cpu_register_physical_memory(sdram_base, sdram_size,
+            phys_sdram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "milkymist.flash", flash_size);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Numonyx JS28F256J3F105 */
+    pflash_cfi01_register(flash_base, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 2,
+                          0x00, 0x89, 0x00, 0x1d, 1);
+
+    /* create irq lines */
+    cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
+    env->pic_state = lm32_pic_init(*cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(env->pic_state, i);
+    }
+
+    /* load bios rom */
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    if (bios_filename) {
+        load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE);
+    }
+
+    reset_info->bootstrap_pc = BIOS_OFFSET;
+
+    /* if no kernel is given no valid bios rom is a fatal error */
+    if (!kernel_filename && !dinfo && !bios_filename) {
+        fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n",
+                bios_name);
+        exit(1);
+    }
+
+    milkymist_uart_create(0x60000000, irq[0], irq[1]);
+    milkymist_sysctl_create(0x60001000, irq[2], irq[3], irq[4],
+            80000000, 0x10014d31, 0x0000041f, 0x00000001);
+    milkymist_hpdmc_create(0x60002000);
+    milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
+    milkymist_memcard_create(0x60004000);
+    milkymist_ac97_create(0x60005000, irq[5], irq[6], irq[7], irq[8]);
+    milkymist_pfpu_create(0x60006000, irq[9]);
+    milkymist_tmu2_create(0x60007000, irq[10]);
+    milkymist_minimac2_create(0x60008000, 0x30000000, irq[11], irq[12]);
+    milkymist_softusb_create(0x6000f000, irq[17],
+            0x20000000, 0x1000, 0x20020000, 0x2000);
+
+    /* make sure juart isn't the first chardev */
+    env->juart_state = lm32_juart_init();
+
+    if (kernel_filename) {
+        uint64_t entry;
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, sdram_base,
+                                              sdram_size);
+            reset_info->bootstrap_pc = sdram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    if (kernel_cmdline && strlen(kernel_cmdline)) {
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
+                kernel_cmdline);
+        reset_info->cmdline_base = (uint32_t)cmdline_base;
+    }
+
+    if (initrd_filename) {
+        size_t initrd_size;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                initrd_max);
+        reset_info->initrd_base = (uint32_t)initrd_base;
+        reset_info->initrd_size = (uint32_t)initrd_size;
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static QEMUMachine milkymist_machine = {
+    .name = "milkymist",
+    .desc = "Milkymist One",
+    .init = milkymist_init,
+    .is_default = 0
+};
+
+static void milkymist_machine_init(void)
+{
+    qemu_register_machine(&milkymist_machine);
+}
+
+machine_init(milkymist_machine_init);
index f5ae63980ccbe0d79649c7684bbacc287aaa996a..420fada25be7df477292b9b71882c718691c1230 100644 (file)
@@ -263,11 +263,9 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     qemu_irq *cpu_exit_irq;
     int via_devfn;
     PCIBus *pci_bus;
-    uint8_t *eeprom_buf;
     i2c_bus *smbus;
     int i;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-    DeviceState *eeprom;
     CPUState *env;
 
     /* init CPUs */
@@ -338,14 +336,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
 
     /* South bridge */
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
-
-    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
-        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
-    }
+    ide_drive_get(hd, MAX_IDE_BUS);
 
     via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
     if (via_devfn < 0) {
@@ -360,13 +351,8 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
 
     smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),
                               0xeee1, NULL);
-    eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
-    memcpy(eeprom_buf, eeprom_spd, sizeof(eeprom_spd));
     /* TODO: Populate SPD eeprom data.  */
-    eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
-    qdev_prop_set_uint8(eeprom, "address", 0x50);
-    qdev_prop_set_ptr(eeprom, "data", eeprom_buf);
-    qdev_init_nofail(eeprom);
+    smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
 
     /* init other devices */
     pit = pit_init(0x40, 0);
index d8baa6d7e3ea751bc97f0b397624ce372fa1ca35..ed2a483c9bdd587f0186a1f501ae4f723fdbd9b5 100644 (file)
@@ -770,7 +770,6 @@ void mips_malta_init (ram_addr_t ram_size,
     qemu_irq *i8259;
     qemu_irq *cpu_exit_irq;
     int piix4_devfn;
-    uint8_t *eeprom_buf;
     i2c_bus *smbus;
     int i;
     DriveInfo *dinfo;
@@ -905,15 +904,7 @@ void mips_malta_init (ram_addr_t ram_size,
     pci_bus = gt64120_register(i8259);
 
     /* Southbridge */
-
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
-
-    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
-        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
-    }
+    ide_drive_get(hd, MAX_IDE_BUS);
 
     piix4_devfn = piix4_init(pci_bus, 80);
     isa_bus_irqs(i8259);
@@ -921,15 +912,8 @@ void mips_malta_init (ram_addr_t ram_size,
     usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
     smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(9),
                           NULL, NULL, 0);
-    eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
-    for (i = 0; i < 8; i++) {
-        /* TODO: Populate SPD eeprom data.  */
-        DeviceState *eeprom;
-        eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
-        qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
-        qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
-        qdev_init_nofail(eeprom);
-    }
+    /* TODO: Populate SPD eeprom data.  */
+    smbus_eeprom_init(smbus, 8, NULL, 0);
     pit = pit_init(0x40, 0);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
index 8feb46163faea44b2461edb5108ae77172abecb2..2834a46d52d8721a7615190093632ea674d859fe 100644 (file)
@@ -287,15 +287,7 @@ void mips_r4k_init (ram_addr_t ram_size,
     if (nd_table[0].vlan)
         isa_ne2000_init(0x300, 9, &nd_table[0]);
 
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
-
-    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
-        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
-    }
-
+    ide_drive_get(hd, MAX_IDE_BUS);
     for(i = 0; i < MAX_IDE_BUS; i++)
         isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
                      hd[MAX_IDE_DEVS * i],
index c5e54ffc359208c5eae19c242a4556262010f59e..26aad51eab7dd5fedde3f9120c3056f6ac2f929e 100644 (file)
@@ -202,44 +202,29 @@ static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-static void mipsnet_save(QEMUFile *f, void *opaque)
-{
-    MIPSnetState *s = opaque;
-
-    qemu_put_be32s(f, &s->busy);
-    qemu_put_be32s(f, &s->rx_count);
-    qemu_put_be32s(f, &s->rx_read);
-    qemu_put_be32s(f, &s->tx_count);
-    qemu_put_be32s(f, &s->tx_written);
-    qemu_put_be32s(f, &s->intctl);
-    qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
-    qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
-}
-
-static int mipsnet_load(QEMUFile *f, void *opaque, int version_id)
-{
-    MIPSnetState *s = opaque;
-
-    if (version_id > 0)
-        return -EINVAL;
-
-    qemu_get_be32s(f, &s->busy);
-    qemu_get_be32s(f, &s->rx_count);
-    qemu_get_be32s(f, &s->rx_read);
-    qemu_get_be32s(f, &s->tx_count);
-    qemu_get_be32s(f, &s->tx_written);
-    qemu_get_be32s(f, &s->intctl);
-    qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
-    qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
-
-    return 0;
-}
+static const VMStateDescription vmstate_mipsnet = {
+    .name = "mipsnet",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(busy, MIPSnetState),
+        VMSTATE_UINT32(rx_count, MIPSnetState),
+        VMSTATE_UINT32(rx_read, MIPSnetState),
+        VMSTATE_UINT32(tx_count, MIPSnetState),
+        VMSTATE_UINT32(tx_written, MIPSnetState),
+        VMSTATE_UINT32(intctl, MIPSnetState),
+        VMSTATE_BUFFER(rx_buffer, MIPSnetState),
+        VMSTATE_BUFFER(tx_buffer, MIPSnetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static void mipsnet_cleanup(VLANClientState *nc)
 {
     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-    unregister_savevm(NULL, "mipsnet", s);
+    vmstate_unregister(NULL, &vmstate_mipsnet, s);
 
     isa_unassign_ioport(s->io_base, 36);
 
@@ -284,5 +269,5 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
     }
 
     mipsnet_reset(s);
-    register_savevm(NULL, "mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
+    vmstate_register(NULL, 0, &vmstate_mipsnet, s);
 }
index 0d2bfb4973b4b5fcd05324188c42a16958b02703..394ed0136e83c0a56258d49eb44febb243f5623e 100644 (file)
@@ -272,7 +272,7 @@ int load_multiboot(void *fw_cfg,
             mb_debug("multiboot loading module: %s\n", initrd_filename);
             mb_mod_length = get_image_size(initrd_filename);
             if (mb_mod_length < 0) {
-                fprintf(stderr, "failed to get %s image size\n", initrd_filename);
+                fprintf(stderr, "Failed to open file '%s'\n", initrd_filename);
                 exit(1);
             }
 
index d98aa8d03c4e60e615a0c7faed230e7f77593f27..52b2931d153d6a223bdbcd3bffa74916d6b9de49 100644 (file)
@@ -1597,11 +1597,11 @@ static void musicpal_init(ram_addr_t ram_size,
     musicpal_misc_init();
 
     dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]);
-    i2c_dev = sysbus_create_simple("gpio_i2c", 0, NULL);
+    i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
     i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c");
 
     lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL);
-    key_dev = sysbus_create_simple("musicpal_key", 0, NULL);
+    key_dev = sysbus_create_simple("musicpal_key", -1, NULL);
 
     /* I2C read data */
     qdev_connect_gpio_out(i2c_dev, 0,
index f414aa139b149b5ccd6c77b958507e20d5feb11c..37e51d7140e1983f12529f7da225485464a00339 100644 (file)
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -52,7 +52,7 @@ struct NANDFlashState {
     BlockDriverState *bdrv;
     int mem_oob;
 
-    int cle, ale, ce, wp, gnd;
+    uint8_t cle, ale, ce, wp, gnd;
 
     uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
     uint8_t *ioaddr;
@@ -66,6 +66,8 @@ struct NANDFlashState {
     void (*blk_write)(NANDFlashState *s);
     void (*blk_erase)(NANDFlashState *s);
     void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset);
+
+    uint32_t ioaddr_vmstate;
 };
 
 # define NAND_NO_AUTOINCR      0x00000001
@@ -281,56 +283,59 @@ static void nand_command(NANDFlashState *s)
     }
 }
 
-static void nand_save(QEMUFile *f, void *opaque)
+static void nand_pre_save(void *opaque)
 {
-    NANDFlashState *s = (NANDFlashState *) opaque;
-    qemu_put_byte(f, s->cle);
-    qemu_put_byte(f, s->ale);
-    qemu_put_byte(f, s->ce);
-    qemu_put_byte(f, s->wp);
-    qemu_put_byte(f, s->gnd);
-    qemu_put_buffer(f, s->io, sizeof(s->io));
-    qemu_put_be32(f, s->ioaddr - s->io);
-    qemu_put_be32(f, s->iolen);
-
-    qemu_put_be32s(f, &s->cmd);
-    qemu_put_be32s(f, &s->addr);
-    qemu_put_be32(f, s->addrlen);
-    qemu_put_be32(f, s->status);
-    qemu_put_be32(f, s->offset);
-    /* XXX: do we want to save s->storage too? */
+    NANDFlashState *s = opaque;
+
+    s->ioaddr_vmstate = s->ioaddr - s->io;
 }
 
-static int nand_load(QEMUFile *f, void *opaque, int version_id)
+static int nand_post_load(void *opaque, int version_id)
 {
-    NANDFlashState *s = (NANDFlashState *) opaque;
-    s->cle = qemu_get_byte(f);
-    s->ale = qemu_get_byte(f);
-    s->ce = qemu_get_byte(f);
-    s->wp = qemu_get_byte(f);
-    s->gnd = qemu_get_byte(f);
-    qemu_get_buffer(f, s->io, sizeof(s->io));
-    s->ioaddr = s->io + qemu_get_be32(f);
-    s->iolen = qemu_get_be32(f);
-    if (s->ioaddr >= s->io + sizeof(s->io) || s->ioaddr < s->io)
+    NANDFlashState *s = opaque;
+
+    if (s->ioaddr_vmstate > sizeof(s->io)) {
         return -EINVAL;
+    }
+    s->ioaddr = s->io + s->ioaddr_vmstate;
 
-    qemu_get_be32s(f, &s->cmd);
-    qemu_get_be32s(f, &s->addr);
-    s->addrlen = qemu_get_be32(f);
-    s->status = qemu_get_be32(f);
-    s->offset = qemu_get_be32(f);
     return 0;
 }
 
+static const VMStateDescription vmstate_nand = {
+    .name = "nand",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = nand_pre_save,
+    .post_load = nand_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(cle, NANDFlashState),
+        VMSTATE_UINT8(ale, NANDFlashState),
+        VMSTATE_UINT8(ce, NANDFlashState),
+        VMSTATE_UINT8(wp, NANDFlashState),
+        VMSTATE_UINT8(gnd, NANDFlashState),
+        VMSTATE_BUFFER(io, NANDFlashState),
+        VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
+        VMSTATE_INT32(iolen, NANDFlashState),
+        VMSTATE_UINT32(cmd, NANDFlashState),
+        VMSTATE_UINT32(addr, NANDFlashState),
+        VMSTATE_INT32(addrlen, NANDFlashState),
+        VMSTATE_INT32(status, NANDFlashState),
+        VMSTATE_INT32(offset, NANDFlashState),
+        /* XXX: do we want to save s->storage too? */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 /*
  * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
  * outputs are R/B and eight I/O pins.
  *
  * CE, WP and R/B are active low.
  */
-void nand_setpins(NANDFlashState *s,
-                int cle, int ale, int ce, int wp, int gnd)
+void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+                  uint8_t ce, uint8_t wp, uint8_t gnd)
 {
     s->cle = cle;
     s->ale = ale;
@@ -502,7 +507,7 @@ NANDFlashState *nand_init(int manf_id, int chip_id)
        is used.  */
     s->ioaddr = s->io;
 
-    register_savevm(NULL, "nand", -1, 0, nand_save, nand_load, s);
+    vmstate_register(NULL, -1, &vmstate_nand, s);
 
     return s;
 }
index 5966359852f101f1aa32233e193c846b552a1775..b668ad1070cd418cf3200ae5a9e125ba6eb2ed59 100644 (file)
@@ -742,7 +742,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
     if (!pci_dev->qdev.hotplugged) {
         static int loaded = 0;
         if (!loaded) {
-            rom_add_option("pxe-ne2k_pci.bin", -1);
+            rom_add_option("pxe-ne2k_pci.rom", -1);
             loaded = 1;
         }
     }
index 06bccbdc4e63cd26b683a789c0e7cd3ab618f276..a7b687bc4197490e81af36fd17a140002a6d3325 100644 (file)
@@ -26,7 +26,6 @@
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "hw.h"
-#include "sysemu.h"
 #include "console.h"
 #include "omap.h"
 #include "boards.h"
index b3ede8941f3f5eb340c4c7f118526dea243729b2..a85214b7f15c1062de4b71fe12c7a2cd2b69e7ad 100644 (file)
@@ -37,6 +37,7 @@
 #include "sysbus.h"
 #include "arch_init.h"
 #include "blockdev.h"
+#include "smbus.h"
 
 #define MAX_IDE_BUS 2
 
@@ -129,15 +130,7 @@ static void pc_init1(ram_addr_t ram_size,
             pci_nic_init_nofail(nd, "e1000", NULL);
     }
 
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
-
-    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
-        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
-    }
-
+    ide_drive_get(hd, MAX_IDE_BUS);
     if (pci_enabled) {
         PCIDevice *dev;
         dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
@@ -162,7 +155,6 @@ static void pc_init1(ram_addr_t ram_size,
     }
 
     if (pci_enabled && acpi_enabled) {
-        uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
         i2c_bus *smbus;
 
         cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
@@ -171,13 +163,7 @@ static void pc_init1(ram_addr_t ram_size,
         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
                               isa_get_irq(9), *cmos_s3, *smi_irq,
                               kvm_enabled());
-        for (i = 0; i < 8; i++) {
-            DeviceState *eeprom;
-            eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
-            qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
-            qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
-            qdev_init_nofail(eeprom);
-        }
+        smbus_eeprom_init(smbus, 8, NULL, 0);
     }
 
     if (i440fx_state) {
index 6a113a9327bb1e4759b064c28c4dae490f2db6e2..9de61490434df2f49e893dfc1fbc831b1fd721d0 100644 (file)
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -18,8 +18,7 @@
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "sysemu.h"
-#include "range.h"
+#include "qemu-common.h"
 #include "pci_bridge.h"
 #include "pcie.h"
 #include "msix.h"
index 4ac3e3297c776a550936db49f12f2cd8b004c7a4..9415a1ecf51f24c3b745ff4bfd02f943c7679079 100644 (file)
@@ -296,7 +296,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
     if (!pci_dev->qdev.hotplugged) {
         static int loaded = 0;
         if (!loaded) {
-            rom_add_option("pxe-pcnet.bin", -1);
+            rom_add_option("pxe-pcnet.rom", -1);
             loaded = 1;
         }
     }
index 82ccbbd2c3881bf3f25d25317de68546342a36f4..cf16fd4d018112635bdcfef57c2d2beec93393a7 100644 (file)
@@ -113,23 +113,23 @@ struct qemu_ether_header {
 #define CSR_XMTRL(S)     ((S)->csr[78])
 #define CSR_MISSC(S)     ((S)->csr[112])
 
-#define CSR_IADR(S)      ((S)->csr[ 1] | ((S)->csr[ 2] << 16))
-#define CSR_CRBA(S)      ((S)->csr[18] | ((S)->csr[19] << 16))
-#define CSR_CXBA(S)      ((S)->csr[20] | ((S)->csr[21] << 16))
-#define CSR_NRBA(S)      ((S)->csr[22] | ((S)->csr[23] << 16))
-#define CSR_BADR(S)      ((S)->csr[24] | ((S)->csr[25] << 16))
-#define CSR_NRDA(S)      ((S)->csr[26] | ((S)->csr[27] << 16))
-#define CSR_CRDA(S)      ((S)->csr[28] | ((S)->csr[29] << 16))
-#define CSR_BADX(S)      ((S)->csr[30] | ((S)->csr[31] << 16))
-#define CSR_NXDA(S)      ((S)->csr[32] | ((S)->csr[33] << 16))
-#define CSR_CXDA(S)      ((S)->csr[34] | ((S)->csr[35] << 16))
-#define CSR_NNRD(S)      ((S)->csr[36] | ((S)->csr[37] << 16))
-#define CSR_NNXD(S)      ((S)->csr[38] | ((S)->csr[39] << 16))
-#define CSR_PXDA(S)      ((S)->csr[60] | ((S)->csr[61] << 16))
-#define CSR_NXBA(S)      ((S)->csr[64] | ((S)->csr[65] << 16))
+#define CSR_IADR(S)      ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16))
+#define CSR_CRBA(S)      ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16))
+#define CSR_CXBA(S)      ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16))
+#define CSR_NRBA(S)      ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16))
+#define CSR_BADR(S)      ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16))
+#define CSR_NRDA(S)      ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16))
+#define CSR_CRDA(S)      ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16))
+#define CSR_BADX(S)      ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16))
+#define CSR_NXDA(S)      ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16))
+#define CSR_CXDA(S)      ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16))
+#define CSR_NNRD(S)      ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16))
+#define CSR_NNXD(S)      ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16))
+#define CSR_PXDA(S)      ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16))
+#define CSR_NXBA(S)      ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16))
 
 #define PHYSADDR(S,A) \
-  (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16))
+  (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16))
 
 struct pcnet_initblk16 {
     uint16_t mode;
index 30c8aa4e4f619cbc93cc0e2f4f5f9fd97e3e0f5e..14bbc34e16c5754b5bb67fae58e43369a5b923a0 100644 (file)
@@ -50,6 +50,8 @@ do {                                               \
 #define DPRINTF(fmt, ...) do { } while (0)
 #endif
 
+#define PFLASH_LAZY_ROMD_THRESHOLD 42
+
 struct pflash_t {
     BlockDriverState *bs;
     target_phys_addr_t base;
@@ -70,6 +72,7 @@ struct pflash_t {
     ram_addr_t off;
     int fl_mem;
     int rom_mode;
+    int read_counter; /* used for lazy switch-back to rom mode */
     void *storage;
 };
 
@@ -112,10 +115,10 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
 
     DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
     ret = -1;
-    if (pfl->rom_mode) {
-        /* Lazy reset of to ROMD mode */
-        if (pfl->wcycle == 0)
-            pflash_register_memory(pfl, 1);
+    /* Lazy reset to ROMD mode after a certain amount of read accesses */
+    if (!pfl->rom_mode && pfl->wcycle == 0 &&
+        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
+        pflash_register_memory(pfl, 1);
     }
     offset &= pfl->chip_len - 1;
     boff = offset & 0xFF;
@@ -254,6 +257,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
         /* Set the device in I/O access mode if required */
         if (pfl->rom_mode)
             pflash_register_memory(pfl, 0);
+        pfl->read_counter = 0;
         /* We're in read mode */
     check_unlock0:
         if (boff == 0x55 && cmd == 0x98) {
index 72073cd0a094da3e292df2fbd0f5992911d18b03..71f1f84dc0444f591e1e48024441f0af21509cb5 100644 (file)
 
 PCIDevice *piix4_dev;
 
+typedef struct PIIX4State {
+    PCIDevice dev;
+} PIIX4State;
+
 static void piix4_reset(void *opaque)
 {
-    PCIDevice *d = opaque;
-    uint8_t *pci_conf = d->config;
+    PIIX4State *d = opaque;
+    uint8_t *pci_conf = d->dev.config;
 
     pci_conf[0x04] = 0x07; // master, memory and I/O
     pci_conf[0x05] = 0x00;
@@ -68,33 +72,30 @@ static void piix4_reset(void *opaque)
     pci_conf[0xae] = 0x00;
 }
 
-static void piix_save(QEMUFile* f, void *opaque)
-{
-    PCIDevice *d = opaque;
-    pci_device_save(d, f);
-}
-
-static int piix_load(QEMUFile* f, void *opaque, int version_id)
-{
-    PCIDevice *d = opaque;
-    if (version_id != 2)
-        return -EINVAL;
-    return pci_device_load(d, f);
-}
+static const VMStateDescription vmstate_piix4 = {
+    .name = "PIIX4",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PIIX4State),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-static int piix4_initfn(PCIDevice *d)
+static int piix4_initfn(PCIDevice *dev)
 {
+    PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev);
     uint8_t *pci_conf;
 
-    isa_bus_new(&d->qdev);
-    register_savevm(&d->qdev, "PIIX4", 0, 2, piix_save, piix_load, d);
+    isa_bus_new(&d->dev.qdev);
 
-    pci_conf = d->config;
+    pci_conf = d->dev.config;
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_0); // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
     pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
 
-    piix4_dev = d;
+    piix4_dev = &d->dev;
     qemu_register_reset(piix4_reset, d);
     return 0;
 }
@@ -111,7 +112,8 @@ static PCIDeviceInfo piix4_info[] = {
     {
         .qdev.name    = "PIIX4",
         .qdev.desc    = "ISA bridge",
-        .qdev.size    = sizeof(PCIDevice),
+        .qdev.size    = sizeof(PIIX4State),
+        .qdev.vmsd    = &vmstate_piix4,
         .qdev.no_user = 1,
         .no_hotplug   = 1,
         .init         = piix4_initfn,
index 77f0dbf137f0ede1aefdef16c2550e67c1081a99..3b94b14cb9bee02021e7fbafd5e1e00b40377e7e 100644 (file)
@@ -235,56 +235,30 @@ static CPUWriteMemoryFunc * const pl011_writefn[] = {
    pl011_write
 };
 
-static void pl011_save(QEMUFile *f, void *opaque)
-{
-    pl011_state *s = (pl011_state *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->readbuff);
-    qemu_put_be32(f, s->flags);
-    qemu_put_be32(f, s->lcr);
-    qemu_put_be32(f, s->cr);
-    qemu_put_be32(f, s->dmacr);
-    qemu_put_be32(f, s->int_enabled);
-    qemu_put_be32(f, s->int_level);
-    for (i = 0; i < 16; i++)
-        qemu_put_be32(f, s->read_fifo[i]);
-    qemu_put_be32(f, s->ilpr);
-    qemu_put_be32(f, s->ibrd);
-    qemu_put_be32(f, s->fbrd);
-    qemu_put_be32(f, s->ifl);
-    qemu_put_be32(f, s->read_pos);
-    qemu_put_be32(f, s->read_count);
-    qemu_put_be32(f, s->read_trigger);
-}
-
-static int pl011_load(QEMUFile *f, void *opaque, int version_id)
-{
-    pl011_state *s = (pl011_state *)opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->readbuff = qemu_get_be32(f);
-    s->flags = qemu_get_be32(f);
-    s->lcr = qemu_get_be32(f);
-    s->cr = qemu_get_be32(f);
-    s->dmacr = qemu_get_be32(f);
-    s->int_enabled = qemu_get_be32(f);
-    s->int_level = qemu_get_be32(f);
-    for (i = 0; i < 16; i++)
-        s->read_fifo[i] = qemu_get_be32(f);
-    s->ilpr = qemu_get_be32(f);
-    s->ibrd = qemu_get_be32(f);
-    s->fbrd = qemu_get_be32(f);
-    s->ifl = qemu_get_be32(f);
-    s->read_pos = qemu_get_be32(f);
-    s->read_count = qemu_get_be32(f);
-    s->read_trigger = qemu_get_be32(f);
-
-    return 0;
-}
+static const VMStateDescription vmstate_pl011 = {
+    .name = "pl011",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(readbuff, pl011_state),
+        VMSTATE_UINT32(flags, pl011_state),
+        VMSTATE_UINT32(lcr, pl011_state),
+        VMSTATE_UINT32(cr, pl011_state),
+        VMSTATE_UINT32(dmacr, pl011_state),
+        VMSTATE_UINT32(int_enabled, pl011_state),
+        VMSTATE_UINT32(int_level, pl011_state),
+        VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16),
+        VMSTATE_UINT32(ilpr, pl011_state),
+        VMSTATE_UINT32(ibrd, pl011_state),
+        VMSTATE_UINT32(fbrd, pl011_state),
+        VMSTATE_UINT32(ifl, pl011_state),
+        VMSTATE_INT32(read_pos, pl011_state),
+        VMSTATE_INT32(read_count, pl011_state),
+        VMSTATE_INT32(read_trigger, pl011_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int pl011_init(SysBusDevice *dev, const unsigned char *id)
 {
@@ -307,7 +281,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
         qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
                               pl011_event, s);
     }
-    register_savevm(&dev->qdev, "pl011_uart", -1, 1, pl011_save, pl011_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
     return 0;
 }
 
index ffe05ab747d466580878464b1c99a1852755896e..00e494a0de4d872da154175ce36c59034c0d2513 100644 (file)
@@ -239,54 +239,42 @@ static CPUWriteMemoryFunc * const pl022_writefn[] = {
    pl022_write
 };
 
-static void pl022_save(QEMUFile *f, void *opaque)
-{
-    pl022_state *s = (pl022_state *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->cr0);
-    qemu_put_be32(f, s->cr1);
-    qemu_put_be32(f, s->bitmask);
-    qemu_put_be32(f, s->sr);
-    qemu_put_be32(f, s->cpsr);
-    qemu_put_be32(f, s->is);
-    qemu_put_be32(f, s->im);
-    qemu_put_be32(f, s->tx_fifo_head);
-    qemu_put_be32(f, s->rx_fifo_head);
-    qemu_put_be32(f, s->tx_fifo_len);
-    qemu_put_be32(f, s->rx_fifo_len);
-    for (i = 0; i < 8; i++) {
-        qemu_put_be16(f, s->tx_fifo[i]);
-        qemu_put_be16(f, s->rx_fifo[i]);
-    }
-}
-
-static int pl022_load(QEMUFile *f, void *opaque, int version_id)
-{
-    pl022_state *s = (pl022_state *)opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->cr0 = qemu_get_be32(f);
-    s->cr1 = qemu_get_be32(f);
-    s->bitmask = qemu_get_be32(f);
-    s->sr = qemu_get_be32(f);
-    s->cpsr = qemu_get_be32(f);
-    s->is = qemu_get_be32(f);
-    s->im = qemu_get_be32(f);
-    s->tx_fifo_head = qemu_get_be32(f);
-    s->rx_fifo_head = qemu_get_be32(f);
-    s->tx_fifo_len = qemu_get_be32(f);
-    s->rx_fifo_len = qemu_get_be32(f);
-    for (i = 0; i < 8; i++) {
-        s->tx_fifo[i] = qemu_get_be16(f);
-        s->rx_fifo[i] = qemu_get_be16(f);
+static const VMStateDescription vmstate_pl022 = {
+    .name = "pl022_ssp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(cr0, pl022_state),
+        VMSTATE_UINT32(cr1, pl022_state),
+        VMSTATE_UINT32(bitmask, pl022_state),
+        VMSTATE_UINT32(sr, pl022_state),
+        VMSTATE_UINT32(cpsr, pl022_state),
+        VMSTATE_UINT32(is, pl022_state),
+        VMSTATE_UINT32(im, pl022_state),
+        VMSTATE_INT32(tx_fifo_head, pl022_state),
+        VMSTATE_INT32(rx_fifo_head, pl022_state),
+        VMSTATE_INT32(tx_fifo_len, pl022_state),
+        VMSTATE_INT32(rx_fifo_len, pl022_state),
+        VMSTATE_UINT16(tx_fifo[0], pl022_state),
+        VMSTATE_UINT16(rx_fifo[0], pl022_state),
+        VMSTATE_UINT16(tx_fifo[1], pl022_state),
+        VMSTATE_UINT16(rx_fifo[1], pl022_state),
+        VMSTATE_UINT16(tx_fifo[2], pl022_state),
+        VMSTATE_UINT16(rx_fifo[2], pl022_state),
+        VMSTATE_UINT16(tx_fifo[3], pl022_state),
+        VMSTATE_UINT16(rx_fifo[3], pl022_state),
+        VMSTATE_UINT16(tx_fifo[4], pl022_state),
+        VMSTATE_UINT16(rx_fifo[4], pl022_state),
+        VMSTATE_UINT16(tx_fifo[5], pl022_state),
+        VMSTATE_UINT16(rx_fifo[5], pl022_state),
+        VMSTATE_UINT16(tx_fifo[6], pl022_state),
+        VMSTATE_UINT16(rx_fifo[6], pl022_state),
+        VMSTATE_UINT16(tx_fifo[7], pl022_state),
+        VMSTATE_UINT16(rx_fifo[7], pl022_state),
+        VMSTATE_END_OF_LIST()
     }
-
-    return 0;
-}
+};
 
 static int pl022_init(SysBusDevice *dev)
 {
@@ -300,7 +288,7 @@ static int pl022_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
     s->ssi = ssi_create_bus(&dev->qdev, "ssi");
     pl022_reset(s);
-    register_savevm(&dev->qdev, "pl022_ssp", -1, 1, pl022_save, pl022_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_pl022, s);
     return 0;
 }
 
diff --git a/hw/ppc-viosrp.h b/hw/ppc-viosrp.h
new file mode 100644 (file)
index 0000000..d8e365d
--- /dev/null
@@ -0,0 +1,216 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* 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, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/*                                                                           */
+/* This file contains structures and definitions for IBM RPA (RS/6000        */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
+/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
+/* commands between logical partitions.                                      */
+/*                                                                           */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
+/* between partitions.  The definitions in this file are architected,        */
+/* and cannot be changed without breaking compatibility with other versions  */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions                                                */
+/*****************************************************************************/
+#ifndef PPC_VIOSRP_H
+#define PPC_VIOSRP_H
+
+#define SRP_VERSION "16.a"
+#define SRP_MAX_IU_LEN    256
+#define SRP_MAX_LOC_LEN 32
+
+union srp_iu {
+    struct srp_login_req login_req;
+    struct srp_login_rsp login_rsp;
+    struct srp_login_rej login_rej;
+    struct srp_i_logout i_logout;
+    struct srp_t_logout t_logout;
+    struct srp_tsk_mgmt tsk_mgmt;
+    struct srp_cmd cmd;
+    struct srp_rsp rsp;
+    uint8_t reserved[SRP_MAX_IU_LEN];
+};
+
+enum viosrp_crq_formats {
+    VIOSRP_SRP_FORMAT = 0x01,
+    VIOSRP_MAD_FORMAT = 0x02,
+    VIOSRP_OS400_FORMAT = 0x03,
+    VIOSRP_AIX_FORMAT = 0x04,
+    VIOSRP_LINUX_FORMAT = 0x06,
+    VIOSRP_INLINE_FORMAT = 0x07
+};
+
+enum viosrp_crq_status {
+    VIOSRP_OK = 0x0,
+    VIOSRP_NONRECOVERABLE_ERR = 0x1,
+    VIOSRP_VIOLATES_MAX_XFER = 0x2,
+    VIOSRP_PARTNER_PANIC = 0x3,
+    VIOSRP_DEVICE_BUSY = 0x8,
+    VIOSRP_ADAPTER_FAIL = 0x10,
+    VIOSRP_OK2 = 0x99,
+};
+
+struct viosrp_crq {
+    uint8_t valid;        /* used by RPA */
+    uint8_t format;        /* SCSI vs out-of-band */
+    uint8_t reserved;
+    uint8_t status;        /* non-scsi failure? (e.g. DMA failure) */
+    uint16_t timeout;        /* in seconds */
+    uint16_t IU_length;        /* in bytes */
+    uint64_t IU_data_ptr;    /* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.
+ */
+enum viosrp_mad_types {
+    VIOSRP_EMPTY_IU_TYPE = 0x01,
+    VIOSRP_ERROR_LOG_TYPE = 0x02,
+    VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+    VIOSRP_HOST_CONFIG_TYPE = 0x04,
+    VIOSRP_CAPABILITIES_TYPE = 0x05,
+    VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+    VIOSRP_MAD_SUCCESS = 0x00,
+    VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+    VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+    MIGRATION_CAPABILITIES = 0x01,
+    RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+    SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+    SERVER_SUPPORTS_CAP = 0x01,
+    SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+    CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+    CLIENT_MIGRATED = 0x01,
+    CLIENT_RECONNECT = 0x02,
+    CAP_LIST_SUPPORTED = 0x04,
+    CAP_LIST_DATA = 0x08,
+};
+
+/*
+ * Common MAD header
+ */
+struct mad_common {
+    uint32_t type;
+    uint16_t status;
+    uint16_t length;
+    uint64_t tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server.  There is no way for the server to send
+ * an asynchronous message back to the client.  The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER
+ */
+struct viosrp_empty_iu {
+    struct mad_common common;
+    uint64_t buffer;
+    uint32_t port;
+};
+
+struct viosrp_error_log {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_adapter_info {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_host_config {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_fast_fail {
+    struct mad_common common;
+};
+
+struct viosrp_capabilities {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct mad_capability_common {
+    uint32_t cap_type;
+    uint16_t length;
+    uint16_t server_support;
+};
+
+struct mad_reserve_cap {
+    struct mad_capability_common common;
+    uint32_t type;
+};
+
+struct mad_migration_cap {
+    struct mad_capability_common common;
+    uint32_t ecl;
+};
+
+struct capabilities {
+    uint32_t flags;
+    char name[SRP_MAX_LOC_LEN];
+    char loc[SRP_MAX_LOC_LEN];
+    struct mad_migration_cap migration;
+    struct mad_reserve_cap reserve;
+};
+
+union mad_iu {
+    struct viosrp_empty_iu empty_iu;
+    struct viosrp_error_log error_log;
+    struct viosrp_adapter_info adapter_info;
+    struct viosrp_host_config host_config;
+    struct viosrp_fast_fail fast_fail;
+    struct viosrp_capabilities capabilities;
+};
+
+union viosrp_iu {
+    union srp_iu srp;
+    union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+    char srp_version[8];
+    char partition_name[96];
+    uint32_t partition_number;
+    uint32_t mad_version;
+    uint32_t os_type;
+    uint32_t port_max_txu[8];    /* per-port maximum transfer */
+};
+
+#endif
index b55a84883eb9168bb390f1e50265d6edccd5b1c4..18733289db96eb9db7dd4f637fcb4d3e0c5fcbaa 100644 (file)
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -247,6 +247,39 @@ void ppc970_irq_init (CPUState *env)
     env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env,
                                                   PPC970_INPUT_NB);
 }
+
+/* POWER7 internal IRQ controller */
+static void power7_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+
+    switch (pin) {
+    case POWER7_INPUT_INT:
+        /* Level sensitive - active high */
+        LOG_IRQ("%s: set the external IRQ state to %d\n",
+                __func__, level);
+        ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+        break;
+    default:
+        /* Unknown pin - do nothing */
+        LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+        return;
+    }
+    if (level) {
+        env->irq_input_state |= 1 << pin;
+    } else {
+        env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppcPOWER7_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, env,
+                                                  POWER7_INPUT_NB);
+}
 #endif /* defined(TARGET_PPC64) */
 
 /* PowerPC 40x internal IRQ controller */
index 34f54cf5da42bddc02d902670b689f12a68e29f8..3ccf13479b31eed9e889d1fa2e8def1bd830a80d 100644 (file)
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -36,6 +36,7 @@ void ppc40x_irq_init (CPUState *env);
 void ppce500_irq_init (CPUState *env);
 void ppc6xx_irq_init (CPUState *env);
 void ppc970_irq_init (CPUState *env);
+void ppcPOWER7_irq_init (CPUState *env);
 
 /* PPC machines for OpenBIOS */
 enum {
index 34ddf454779b5bdada423dd22d4d8c603971aabe..20b862939ea981db514f4bcb61d7f1a45602481d 100644 (file)
@@ -17,7 +17,6 @@
 #include "hw.h"
 #include "pci.h"
 #include "boards.h"
-#include "sysemu.h"
 #include "ppc440.h"
 #include "kvm.h"
 #include "kvm_ppc.h"
@@ -156,8 +155,6 @@ static void bamboo_init(ram_addr_t ram_size,
             exit(1);
         }
 
-        cpu_synchronize_state(env);
-
         /* Set initial guest state. */
         env->gpr[1] = (16<<20) - 8;
         env->gpr[3] = FDT_ADDR;
index 5f581fe2c4eaee80c4b44fd05febc333e2863c72..7f9ed171384151b42e0ced79637a43ceff1dee02 100644 (file)
@@ -24,7 +24,6 @@
 #include "hw.h"
 #include "ppc.h"
 #include "ppc4xx.h"
-#include "sysemu.h"
 #include "qemu-log.h"
 
 //#define DEBUG_MMIO
index f62f1f91d52cc78b64ff06259115e35399040f1d..299473c4b5179764a35492971e33aaa72067b723 100644 (file)
@@ -285,50 +285,48 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pci_irqs[irq_num], level);
 }
 
-static void ppc4xx_pci_save(QEMUFile *f, void *opaque)
-{
-    PPC4xxPCIState *controller = opaque;
-    int i;
-
-    pci_device_save(controller->pci_dev, f);
-
-    for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
-        qemu_put_be32s(f, &controller->pmm[i].la);
-        qemu_put_be32s(f, &controller->pmm[i].ma);
-        qemu_put_be32s(f, &controller->pmm[i].pcila);
-        qemu_put_be32s(f, &controller->pmm[i].pciha);
-    }
-
-    for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
-        qemu_put_be32s(f, &controller->ptm[i].ms);
-        qemu_put_be32s(f, &controller->ptm[i].la);
+static const VMStateDescription vmstate_pci_master_map = {
+    .name = "pci_master_map",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(la, struct PCIMasterMap),
+        VMSTATE_UINT32(ma, struct PCIMasterMap),
+        VMSTATE_UINT32(pcila, struct PCIMasterMap),
+        VMSTATE_UINT32(pciha, struct PCIMasterMap),
+        VMSTATE_END_OF_LIST()
     }
-}
-
-static int ppc4xx_pci_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PPC4xxPCIState *controller = opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    pci_device_load(controller->pci_dev, f);
+};
 
-    for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
-        qemu_get_be32s(f, &controller->pmm[i].la);
-        qemu_get_be32s(f, &controller->pmm[i].ma);
-        qemu_get_be32s(f, &controller->pmm[i].pcila);
-        qemu_get_be32s(f, &controller->pmm[i].pciha);
+static const VMStateDescription vmstate_pci_target_map = {
+    .name = "pci_target_map",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(ms, struct PCITargetMap),
+        VMSTATE_UINT32(la, struct PCITargetMap),
+        VMSTATE_END_OF_LIST()
     }
+};
 
-    for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
-        qemu_get_be32s(f, &controller->ptm[i].ms);
-        qemu_get_be32s(f, &controller->ptm[i].la);
+static const VMStateDescription vmstate_ppc4xx_pci = {
+    .name = "ppc4xx_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState),
+        VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1,
+                             vmstate_pci_master_map,
+                             struct PCIMasterMap),
+        VMSTATE_STRUCT_ARRAY(ptm, PPC4xxPCIState, PPC4xx_PCI_NR_PTMS, 1,
+                             vmstate_pci_target_map,
+                             struct PCITargetMap),
+        VMSTATE_END_OF_LIST()
     }
-
-    return 0;
-}
+};
 
 /* XXX Interrupt acknowledge cycles not supported. */
 PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
@@ -381,8 +379,8 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
     qemu_register_reset(ppc4xx_pci_reset, controller);
 
     /* XXX load/save code not tested. */
-    register_savevm(&controller->pci_dev->qdev, "ppc4xx_pci", ppc4xx_pci_id++,
-                    1, ppc4xx_pci_save, ppc4xx_pci_load, controller);
+    vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++,
+                     &vmstate_ppc4xx_pci, controller);
 
     return controller->pci_state.bus;
 
index b9245f066a12bb8ed4a37cc85a4ac462fd6981b6..86f1cfbee98c465f4a7edf350dd9487213495c15 100644 (file)
@@ -325,20 +325,13 @@ static void ppc_core99_init (ram_addr_t ram_size,
     for(i = 0; i < nb_nics; i++)
         pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
 
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
+    ide_drive_get(hd, MAX_IDE_BUS);
     dbdma = DBDMA_init(&dbdma_mem_index);
 
     /* We only emulate 2 out of 3 IDE controllers for now */
     ide_mem_index[0] = -1;
-    hd[0] = drive_get(IF_IDE, 0, 0);
-    hd[1] = drive_get(IF_IDE, 0, 1);
     ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]);
-    hd[0] = drive_get(IF_IDE, 1, 0);
-    hd[1] = drive_get(IF_IDE, 1, 1);
-    ide_mem_index[2] = pmac_ide_init(hd, pic[0x0e], dbdma, 0x1a, pic[0x02]);
+    ide_mem_index[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]);
 
     /* cuda also initialize ADB */
     if (machine_arch == ARCH_MAC99_U3) {
index 8a4e088a384ff0560ea0922e5a998a7cb616be90..75a312742e3874c758021d25234eef947fa8bf6a 100644 (file)
@@ -236,21 +236,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
 
 
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
+    ide_drive_get(hd, MAX_IDE_BUS);
 
     /* First IDE channel is a MAC IDE on the MacIO bus */
-    hd[0] = drive_get(IF_IDE, 0, 0);
-    hd[1] = drive_get(IF_IDE, 0, 1);
     dbdma = DBDMA_init(&dbdma_mem_index);
     ide_mem_index[0] = -1;
     ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]);
 
     /* Second IDE channel is a CMD646 on the PCI bus */
-    hd[0] = drive_get(IF_IDE, 1, 0);
-    hd[1] = drive_get(IF_IDE, 1, 1);
+    hd[0] = hd[MAX_IDE_DEVS];
+    hd[1] = hd[MAX_IDE_DEVS + 1];
     hd[3] = hd[2] = NULL;
     pci_cmd646_ide_init(pci_bus, hd, 0);
 
index 5615ef9ad84e07ea99e69f30c7edb3bed42e82a9..0e9cfc24cda129e16f89f7f7709b2651b1b524d0 100644 (file)
@@ -681,15 +681,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
         }
     }
 
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
-
-    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
-        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
-    }
-
+    ide_drive_get(hd, MAX_IDE_BUS);
     for(i = 0; i < MAX_IDE_BUS; i++) {
         isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
                      hd[2 * i],
index b7670ae27ce6f48947eba35f4ea2f808081cb134..e111dda5f4c6de1f8a4686ff22de736cd2b6cfba 100644 (file)
@@ -268,8 +268,6 @@ static void mpc8544ds_init(ram_addr_t ram_size,
             exit(1);
         }
 
-        cpu_synchronize_state(env);
-
         /* Set initial guest state. */
         env->gpr[1] = (16<<20) - 8;
         env->gpr[3] = dt_base;
index 11edd03f16f56c396336f7459fe1438070ce84ae..83a20e462028a0829acbaad52ce30e078293e12e 100644 (file)
@@ -198,7 +198,7 @@ static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
             ret = (irq_num + devno - 0x10) % 4;
             break;
         default:
-            printf("Error:%s:unknow dev number\n", __func__);
+            printf("Error:%s:unknown dev number\n", __func__);
     }
 
     pci_debug("%s: devfn %x irq %d -> %d  devno:%x\n", __func__,
@@ -216,56 +216,49 @@ static void mpc85xx_pci_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pic[irq_num], level);
 }
 
-static void ppce500_pci_save(QEMUFile *f, void *opaque)
-{
-    PPCE500PCIState *controller = opaque;
-    int i;
-
-    pci_device_save(controller->pci_dev, f);
-
-    for (i = 0; i < PPCE500_PCI_NR_POBS; i++) {
-        qemu_put_be32s(f, &controller->pob[i].potar);
-        qemu_put_be32s(f, &controller->pob[i].potear);
-        qemu_put_be32s(f, &controller->pob[i].powbar);
-        qemu_put_be32s(f, &controller->pob[i].powar);
-    }
-
-    for (i = 0; i < PPCE500_PCI_NR_PIBS; i++) {
-        qemu_put_be32s(f, &controller->pib[i].pitar);
-        qemu_put_be32s(f, &controller->pib[i].piwbar);
-        qemu_put_be32s(f, &controller->pib[i].piwbear);
-        qemu_put_be32s(f, &controller->pib[i].piwar);
+static const VMStateDescription vmstate_pci_outbound = {
+    .name = "pci_outbound",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(potar, struct pci_outbound),
+        VMSTATE_UINT32(potear, struct pci_outbound),
+        VMSTATE_UINT32(powbar, struct pci_outbound),
+        VMSTATE_UINT32(powar, struct pci_outbound),
+        VMSTATE_END_OF_LIST()
     }
-    qemu_put_be32s(f, &controller->gasket_time);
-}
-
-static int ppce500_pci_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PPCE500PCIState *controller = opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    pci_device_load(controller->pci_dev, f);
+};
 
-    for (i = 0; i < PPCE500_PCI_NR_POBS; i++) {
-        qemu_get_be32s(f, &controller->pob[i].potar);
-        qemu_get_be32s(f, &controller->pob[i].potear);
-        qemu_get_be32s(f, &controller->pob[i].powbar);
-        qemu_get_be32s(f, &controller->pob[i].powar);
+static const VMStateDescription vmstate_pci_inbound = {
+    .name = "pci_inbound",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(pitar, struct pci_inbound),
+        VMSTATE_UINT32(piwbar, struct pci_inbound),
+        VMSTATE_UINT32(piwbear, struct pci_inbound),
+        VMSTATE_UINT32(piwar, struct pci_inbound),
+        VMSTATE_END_OF_LIST()
     }
+};
 
-    for (i = 0; i < PPCE500_PCI_NR_PIBS; i++) {
-        qemu_get_be32s(f, &controller->pib[i].pitar);
-        qemu_get_be32s(f, &controller->pib[i].piwbar);
-        qemu_get_be32s(f, &controller->pib[i].piwbear);
-        qemu_get_be32s(f, &controller->pib[i].piwar);
+static const VMStateDescription vmstate_ppce500_pci = {
+    .name = "ppce500_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPCE500PCIState),
+        VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
+                             vmstate_pci_outbound, struct pci_outbound),
+        VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
+                             vmstate_pci_outbound, struct pci_inbound),
+        VMSTATE_UINT32(gasket_time, PPCE500PCIState),
+        VMSTATE_END_OF_LIST()
     }
-    qemu_get_be32s(f, &controller->gasket_time);
-
-    return 0;
-}
+};
 
 PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
 {
@@ -314,8 +307,8 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
                                    PCIE500_REG_SIZE, index);
 
     /* XXX load/save code not tested. */
-    register_savevm(&d->qdev, "ppce500_pci", ppce500_pci_id++,
-                    1, ppce500_pci_save, ppce500_pci_load, controller);
+    vmstate_register(&d->qdev, ppce500_pci_id++, &vmstate_ppce500_pci,
+                     controller);
 
     return controller->pci_state.bus;
 
index e68c1d14158d78dfb307b39552fed2cfcb2e7de4..47964a67e1644ebcd4c413b89985a6749acf5eb0 100644 (file)
@@ -11,7 +11,7 @@
 
 struct ptimer_state
 {
-    int enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot.  */
+    uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot.  */
     uint64_t limit;
     uint64_t delta;
     uint32_t period_frac;
@@ -188,49 +188,22 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
     }
 }
 
-void qemu_put_ptimer(QEMUFile *f, ptimer_state *s)
-{
-    qemu_put_byte(f, s->enabled);
-    qemu_put_be64s(f, &s->limit);
-    qemu_put_be64s(f, &s->delta);
-    qemu_put_be32s(f, &s->period_frac);
-    qemu_put_sbe64s(f, &s->period);
-    qemu_put_sbe64s(f, &s->last_event);
-    qemu_put_sbe64s(f, &s->next_event);
-    qemu_put_timer(f, s->timer);
-}
-
-void qemu_get_ptimer(QEMUFile *f, ptimer_state *s)
-{
-    s->enabled = qemu_get_byte(f);
-    qemu_get_be64s(f, &s->limit);
-    qemu_get_be64s(f, &s->delta);
-    qemu_get_be32s(f, &s->period_frac);
-    qemu_get_sbe64s(f, &s->period);
-    qemu_get_sbe64s(f, &s->last_event);
-    qemu_get_sbe64s(f, &s->next_event);
-    qemu_get_timer(f, s->timer);
-}
-
-static int get_ptimer(QEMUFile *f, void *pv, size_t size)
-{
-    ptimer_state *v = pv;
-
-    qemu_get_ptimer(f, v);
-    return 0;
-}
-
-static void put_ptimer(QEMUFile *f, void *pv, size_t size)
-{
-    ptimer_state *v = pv;
-
-    qemu_put_ptimer(f, v);
-}
-
-const VMStateInfo vmstate_info_ptimer = {
+const VMStateDescription vmstate_ptimer = {
     .name = "ptimer",
-    .get  = get_ptimer,
-    .put  = put_ptimer,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(enabled, ptimer_state),
+        VMSTATE_UINT64(limit, ptimer_state),
+        VMSTATE_UINT64(delta, ptimer_state),
+        VMSTATE_UINT32(period_frac, ptimer_state),
+        VMSTATE_INT64(period, ptimer_state),
+        VMSTATE_INT64(last_event, ptimer_state),
+        VMSTATE_INT64(next_event, ptimer_state),
+        VMSTATE_TIMER(timer, ptimer_state),
+        VMSTATE_END_OF_LIST()
+    }
 };
 
 ptimer_state *ptimer_init(QEMUBH *bh)
index 9b95e2c8e20ad46d41f2aa1d25e2cf7037ee780d..ac5d95d7186c23cb8b802917fac9aaee111bb5be 100644 (file)
@@ -146,25 +146,16 @@ static CPUWriteMemoryFunc * const pxa2xx_pm_writefn[] = {
     pxa2xx_pm_write,
 };
 
-static void pxa2xx_pm_save(QEMUFile *f, void *opaque)
-{
-    PXA2xxState *s = (PXA2xxState *) opaque;
-    int i;
-
-    for (i = 0; i < 0x40; i ++)
-        qemu_put_be32s(f, &s->pm_regs[i]);
-}
-
-static int pxa2xx_pm_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxState *s = (PXA2xxState *) opaque;
-    int i;
-
-    for (i = 0; i < 0x40; i ++)
-        qemu_get_be32s(f, &s->pm_regs[i]);
-
-    return 0;
-}
+static const VMStateDescription vmstate_pxa2xx_pm = {
+    .name = "pxa2xx_pm",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 #define CCCR   0x00    /* Core Clock Configuration register */
 #define CKEN   0x04    /* Clock Enable register */
@@ -227,29 +218,18 @@ static CPUWriteMemoryFunc * const pxa2xx_cm_writefn[] = {
     pxa2xx_cm_write,
 };
 
-static void pxa2xx_cm_save(QEMUFile *f, void *opaque)
-{
-    PXA2xxState *s = (PXA2xxState *) opaque;
-    int i;
-
-    for (i = 0; i < 4; i ++)
-        qemu_put_be32s(f, &s->cm_regs[i]);
-    qemu_put_be32s(f, &s->clkcfg);
-    qemu_put_be32s(f, &s->pmnc);
-}
-
-static int pxa2xx_cm_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxState *s = (PXA2xxState *) opaque;
-    int i;
-
-    for (i = 0; i < 4; i ++)
-        qemu_get_be32s(f, &s->cm_regs[i]);
-    qemu_get_be32s(f, &s->clkcfg);
-    qemu_get_be32s(f, &s->pmnc);
-
-    return 0;
-}
+static const VMStateDescription vmstate_pxa2xx_cm = {
+    .name = "pxa2xx_cm",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
+        VMSTATE_UINT32(clkcfg, PXA2xxState),
+        VMSTATE_UINT32(pmnc, PXA2xxState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm)
 {
@@ -527,25 +507,16 @@ static CPUWriteMemoryFunc * const pxa2xx_mm_writefn[] = {
     pxa2xx_mm_write,
 };
 
-static void pxa2xx_mm_save(QEMUFile *f, void *opaque)
-{
-    PXA2xxState *s = (PXA2xxState *) opaque;
-    int i;
-
-    for (i = 0; i < 0x1a; i ++)
-        qemu_put_be32s(f, &s->mm_regs[i]);
-}
-
-static int pxa2xx_mm_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxState *s = (PXA2xxState *) opaque;
-    int i;
-
-    for (i = 0; i < 0x1a; i ++)
-        qemu_get_be32s(f, &s->mm_regs[i]);
-
-    return 0;
-}
+static const VMStateDescription vmstate_pxa2xx_mm = {
+    .name = "pxa2xx_mm",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 /* Synchronous Serial Ports */
 typedef struct {
@@ -1748,39 +1719,23 @@ static CPUWriteMemoryFunc * const pxa2xx_i2s_writefn[] = {
     pxa2xx_i2s_write,
 };
 
-static void pxa2xx_i2s_save(QEMUFile *f, void *opaque)
-{
-    PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
-
-    qemu_put_be32s(f, &s->control[0]);
-    qemu_put_be32s(f, &s->control[1]);
-    qemu_put_be32s(f, &s->status);
-    qemu_put_be32s(f, &s->mask);
-    qemu_put_be32s(f, &s->clk);
-
-    qemu_put_be32(f, s->enable);
-    qemu_put_be32(f, s->rx_len);
-    qemu_put_be32(f, s->tx_len);
-    qemu_put_be32(f, s->fifo_len);
-}
-
-static int pxa2xx_i2s_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
-
-    qemu_get_be32s(f, &s->control[0]);
-    qemu_get_be32s(f, &s->control[1]);
-    qemu_get_be32s(f, &s->status);
-    qemu_get_be32s(f, &s->mask);
-    qemu_get_be32s(f, &s->clk);
-
-    s->enable = qemu_get_be32(f);
-    s->rx_len = qemu_get_be32(f);
-    s->tx_len = qemu_get_be32(f);
-    s->fifo_len = qemu_get_be32(f);
-
-    return 0;
-}
+static const VMStateDescription vmstate_pxa2xx_i2s = {
+    .name = "pxa2xx_i2s",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
+        VMSTATE_UINT32(status, PXA2xxI2SState),
+        VMSTATE_UINT32(mask, PXA2xxI2SState),
+        VMSTATE_UINT32(clk, PXA2xxI2SState),
+        VMSTATE_INT32(enable, PXA2xxI2SState),
+        VMSTATE_INT32(rx_len, PXA2xxI2SState),
+        VMSTATE_INT32(tx_len, PXA2xxI2SState),
+        VMSTATE_INT32(fifo_len, PXA2xxI2SState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
 {
@@ -1822,8 +1777,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base,
                     pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x100000, iomemtype);
 
-    register_savevm(NULL, "pxa2xx_i2s", base, 0,
-                    pxa2xx_i2s_save, pxa2xx_i2s_load, s);
+    vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s);
 
     return s;
 }
@@ -2188,7 +2142,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
     iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
                     pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
-    register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
 
     cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
 
@@ -2199,13 +2153,13 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
     iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
                     pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
-    register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
 
     s->pm_base = 0x40f00000;
     iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
                     pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
-    register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
 
     for (i = 0; pxa27x_ssp[i].io_base; i ++);
     s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i);
@@ -2324,7 +2278,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
     iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
                     pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
-    register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
 
     cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
 
@@ -2335,13 +2289,13 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
     iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
                     pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
-    register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
 
     s->pm_base = 0x40f00000;
     iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
                     pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
-    register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
 
     for (i = 0; pxa255_ssp[i].io_base; i ++);
     s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i);
index d77dbf17930bb9ac34a17ced6f9e4428eb626afa..10ef154aa1e500d2390241e3b6df7914c05d7c89 100644 (file)
@@ -289,40 +289,22 @@ static CPUWriteMemoryFunc * const pxa2xx_keypad_writefn[] = {
     pxa2xx_keypad_write
 };
 
-static void pxa2xx_keypad_save(QEMUFile *f, void *opaque)
-{
-    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-
-    qemu_put_be32s(f, &s->kpc);
-    qemu_put_be32s(f, &s->kpdk);
-    qemu_put_be32s(f, &s->kprec);
-    qemu_put_be32s(f, &s->kpmk);
-    qemu_put_be32s(f, &s->kpas);
-    qemu_put_be32s(f, &s->kpasmkp[0]);
-    qemu_put_be32s(f, &s->kpasmkp[1]);
-    qemu_put_be32s(f, &s->kpasmkp[2]);
-    qemu_put_be32s(f, &s->kpasmkp[3]);
-    qemu_put_be32s(f, &s->kpkdi);
-
-}
-
-static int pxa2xx_keypad_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-
-    qemu_get_be32s(f, &s->kpc);
-    qemu_get_be32s(f, &s->kpdk);
-    qemu_get_be32s(f, &s->kprec);
-    qemu_get_be32s(f, &s->kpmk);
-    qemu_get_be32s(f, &s->kpas);
-    qemu_get_be32s(f, &s->kpasmkp[0]);
-    qemu_get_be32s(f, &s->kpasmkp[1]);
-    qemu_get_be32s(f, &s->kpasmkp[2]);
-    qemu_get_be32s(f, &s->kpasmkp[3]);
-    qemu_get_be32s(f, &s->kpkdi);
-
-    return 0;
-}
+static const VMStateDescription vmstate_pxa2xx_keypad = {
+    .name = "pxa2xx_keypad",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
+        VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
+        VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base,
         qemu_irq irq)
@@ -337,8 +319,7 @@ PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base,
                     pxa2xx_keypad_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00100000, iomemtype);
 
-    register_savevm(NULL, "pxa2xx_keypad", 0, 0,
-                    pxa2xx_keypad_save, pxa2xx_keypad_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
 
     return s;
 }
index 5b2b07e02cbfe1a0ae1889d7255fc467c13e2f43..e5248023f817a28e508227d32956244dea43bbe0 100644 (file)
 #include "sysemu.h"
 #include "framebuffer.h"
 
+struct DMAChannel {
+    target_phys_addr_t branch;
+    uint8_t up;
+    uint8_t palette[1024];
+    uint8_t pbuffer[1024];
+    void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr,
+                   int *miny, int *maxy);
+
+    target_phys_addr_t descriptor;
+    target_phys_addr_t source;
+    uint32_t id;
+    uint32_t command;
+};
+
 struct PXA2xxLCDState {
     qemu_irq irq;
     int irqlevel;
@@ -50,19 +64,7 @@ struct PXA2xxLCDState {
     uint32_t liidr;
     uint8_t bscntr;
 
-    struct {
-        target_phys_addr_t branch;
-        int up;
-        uint8_t palette[1024];
-        uint8_t pbuffer[1024];
-        void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr,
-                        int *miny, int *maxy);
-
-        target_phys_addr_t descriptor;
-        target_phys_addr_t source;
-        uint32_t id;
-        uint32_t command;
-    } dma_ch[7];
+    struct DMAChannel dma_ch[7];
 
     qemu_irq vsync_cb;
     int orientation;
@@ -831,74 +833,26 @@ static void pxa2xx_lcdc_orientation(void *opaque, int angle)
     pxa2xx_lcdc_resize(s);
 }
 
-static void pxa2xx_lcdc_save(QEMUFile *f, void *opaque)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    int i;
-
-    qemu_put_be32(f, s->irqlevel);
-    qemu_put_be32(f, s->transp);
-
-    for (i = 0; i < 6; i ++)
-        qemu_put_be32s(f, &s->control[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->status[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->ovl1c[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->ovl2c[i]);
-    qemu_put_be32s(f, &s->ccr);
-    qemu_put_be32s(f, &s->cmdcr);
-    qemu_put_be32s(f, &s->trgbr);
-    qemu_put_be32s(f, &s->tcr);
-    qemu_put_be32s(f, &s->liidr);
-    qemu_put_8s(f, &s->bscntr);
-
-    for (i = 0; i < 7; i ++) {
-        qemu_put_betl(f, s->dma_ch[i].branch);
-        qemu_put_byte(f, s->dma_ch[i].up);
-        qemu_put_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer));
-
-        qemu_put_betl(f, s->dma_ch[i].descriptor);
-        qemu_put_betl(f, s->dma_ch[i].source);
-        qemu_put_be32s(f, &s->dma_ch[i].id);
-        qemu_put_be32s(f, &s->dma_ch[i].command);
+static const VMStateDescription vmstate_dma_channel = {
+    .name = "dma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINTTL(branch, struct DMAChannel),
+        VMSTATE_UINT8(up, struct DMAChannel),
+        VMSTATE_BUFFER(pbuffer, struct DMAChannel),
+        VMSTATE_UINTTL(descriptor, struct DMAChannel),
+        VMSTATE_UINTTL(source, struct DMAChannel),
+        VMSTATE_UINT32(id, struct DMAChannel),
+        VMSTATE_UINT32(command, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
     }
-}
+};
 
-static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id)
+static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
 {
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    int i;
-
-    s->irqlevel = qemu_get_be32(f);
-    s->transp = qemu_get_be32(f);
-
-    for (i = 0; i < 6; i ++)
-        qemu_get_be32s(f, &s->control[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->status[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->ovl1c[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->ovl2c[i]);
-    qemu_get_be32s(f, &s->ccr);
-    qemu_get_be32s(f, &s->cmdcr);
-    qemu_get_be32s(f, &s->trgbr);
-    qemu_get_be32s(f, &s->tcr);
-    qemu_get_be32s(f, &s->liidr);
-    qemu_get_8s(f, &s->bscntr);
-
-    for (i = 0; i < 7; i ++) {
-        s->dma_ch[i].branch = qemu_get_betl(f);
-        s->dma_ch[i].up = qemu_get_byte(f);
-        qemu_get_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer));
-
-        s->dma_ch[i].descriptor = qemu_get_betl(f);
-        s->dma_ch[i].source = qemu_get_betl(f);
-        qemu_get_be32s(f, &s->dma_ch[i].id);
-        qemu_get_be32s(f, &s->dma_ch[i].command);
-    }
+    PXA2xxLCDState *s = opaque;
 
     s->bpp = LCCR3_BPP(s->control[3]);
     s->xres = s->yres = s->pal_for = -1;
@@ -906,6 +860,31 @@ static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
+static const VMStateDescription vmstate_pxa2xx_lcdc = {
+    .name = "pxa2xx_lcdc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = pxa2xx_lcdc_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(irqlevel, PXA2xxLCDState),
+        VMSTATE_INT32(transp, PXA2xxLCDState),
+        VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
+        VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
+        VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
+        VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
+        VMSTATE_UINT32(ccr, PXA2xxLCDState),
+        VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
+        VMSTATE_UINT32(trgbr, PXA2xxLCDState),
+        VMSTATE_UINT32(tcr, PXA2xxLCDState),
+        VMSTATE_UINT32(liidr, PXA2xxLCDState),
+        VMSTATE_UINT8(bscntr, PXA2xxLCDState),
+        VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
+                             vmstate_dma_channel, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 #define BITS 8
 #include "pxa2xx_template.h"
 #define BITS 15
@@ -970,8 +949,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq)
         exit(1);
     }
 
-    register_savevm(NULL, "pxa2xx_lcdc", 0, 0,
-                    pxa2xx_lcdc_save, pxa2xx_lcdc_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
 
     return s;
 }
index 1088a26f8e7212ea8b4c641228005758cc26af8e..eff2d2494559cd5830db8a76c18bc8aec7b4087b 100644 (file)
@@ -354,10 +354,10 @@ static int parse_chr(DeviceState *dev, Property *prop, const char *str)
     if (*ptr == NULL) {
         return -ENOENT;
     }
-    if ((*ptr)->assigned) {
+    if ((*ptr)->avail_connections < 1) {
         return -EEXIST;
     }
-    (*ptr)->assigned = 1;
+    --(*ptr)->avail_connections;
     return 0;
 }
 
index 1aa1ea0e264f96ecf7c6b95b147dab036581162a..9519f5dd57a53184175804edfaf30fa53758f9bc 100644 (file)
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -358,7 +358,8 @@ int qdev_simple_unplug_cb(DeviceState *dev)
     return 0;
 }
 
-/* Like qdev_init(), but terminate program via hw_error() instead of
+
+/* Like qdev_init(), but terminate program via error_report() instead of
    returning an error value.  This is okay during machine creation.
    Don't use for hotplug, because there callers need to recover from
    failure.  Exception: if you know the device's init() callback can't
index d30230a8594f66eda581ed0ae9fa678526361d47..6563336dd04e02c9a7e71d2015d3fc838751e393 100644 (file)
@@ -307,7 +307,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
         if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) {
             target_phys_addr_t dest = s->cache_ptag & ~0x1;
             dest += (s->cache_maint & 0x3) << 3;
-            cpu_physical_memory_rw(dest, (uint8_t*)&val, 4, 1);
+            cpu_physical_memory_write(dest, &val, 4);
         }
         break;
     /* Remote Speed Registers */
@@ -704,7 +704,7 @@ void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, i
         entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
         /* XXX: not sure. should we really use only lowest bits? */
         entry_addr &= 0x7fffffff;
-        cpu_physical_memory_rw(entry_addr, (uint8_t *)&entry, sizeof(entry), 0);
+        cpu_physical_memory_read(entry_addr, &entry, sizeof(entry));
 
         /* Read/write data at right place */
         phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1));
index a67861ec3c9956bac7787c3ed0d07f9419d2f2a3..96fb9da2415ef97bde497975b026c79083f1f203 100644 (file)
@@ -288,8 +288,8 @@ static void realview_init(ram_addr_t ram_size,
     for(n = 0; n < nb_nics; n++) {
         nd = &nd_table[n];
 
-        if ((!nd->model && !done_nic)
-            || strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0) {
+        if (!done_nic && (!nd->model ||
+                    strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) {
             if (is_pb) {
                 lan9118_init(nd, 0x4e000000, pic[28]);
             } else {
index 822038daae3719466fc88c3cc187fca0e92d98dd..c7c7a3cdfb6a4ecec0d9cd370bb152b0de85209a 100644 (file)
 #define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
 
 #if defined (DEBUG_RTL8139)
-#  define DEBUG_PRINT(x) do { printf x ; } while (0)
+#  define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0)
 #else
-#  define DEBUG_PRINT(x)
+static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)
+{
+    return 0;
+}
 #endif
 
 /* Symbolic offsets to registers. */
@@ -510,7 +514,7 @@ static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time);
 
 static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
 {
-    DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command));
+    DPRINTF("eeprom command 0x%02x\n", command);
 
     switch (command & Chip9346_op_mask)
     {
@@ -521,8 +525,8 @@ static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
             eeprom->eedo = 0;
             eeprom->tick = 0;
             eeprom->mode = Chip9346_data_read;
-            DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n",
-                   eeprom->address, eeprom->output));
+            DPRINTF("eeprom read from address 0x%02x data=0x%04x\n",
+                eeprom->address, eeprom->output);
         }
         break;
 
@@ -532,8 +536,8 @@ static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
             eeprom->input = 0;
             eeprom->tick = 0;
             eeprom->mode = Chip9346_none; /* Chip9346_data_write */
-            DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n",
-                   eeprom->address));
+            DPRINTF("eeprom begin write to address 0x%02x\n",
+                eeprom->address);
         }
         break;
         default:
@@ -541,13 +545,13 @@ static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
             switch (command & Chip9346_op_ext_mask)
             {
                 case Chip9346_op_write_enable:
-                    DEBUG_PRINT(("RTL8139: eeprom write enabled\n"));
+                    DPRINTF("eeprom write enabled\n");
                     break;
                 case Chip9346_op_write_all:
-                    DEBUG_PRINT(("RTL8139: eeprom begin write all\n"));
+                    DPRINTF("eeprom begin write all\n");
                     break;
                 case Chip9346_op_write_disable:
-                    DEBUG_PRINT(("RTL8139: eeprom write disabled\n"));
+                    DPRINTF("eeprom write disabled\n");
                     break;
             }
             break;
@@ -560,7 +564,8 @@ static void prom9346_shift_clock(EEprom9346 *eeprom)
 
     ++ eeprom->tick;
 
-    DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo));
+    DPRINTF("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi,
+        eeprom->eedo);
 
     switch (eeprom->mode)
     {
@@ -570,7 +575,7 @@ static void prom9346_shift_clock(EEprom9346 *eeprom)
                 eeprom->mode = Chip9346_read_command;
                 eeprom->tick = 0;
                 eeprom->input = 0;
-                DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n"));
+                DPRINTF("eeprom: +++ synchronized, begin command read\n");
             }
             break;
 
@@ -595,7 +600,7 @@ static void prom9346_shift_clock(EEprom9346 *eeprom)
                 eeprom->input = 0;
                 eeprom->tick = 0;
 
-                DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n"));
+                DPRINTF("eeprom: +++ end of read, awaiting next command\n");
 #else
         // original behaviour
                 ++eeprom->address;
@@ -603,8 +608,8 @@ static void prom9346_shift_clock(EEprom9346 *eeprom)
                 eeprom->output = eeprom->contents[eeprom->address];
                 eeprom->tick = 0;
 
-                DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n",
-                       eeprom->address, eeprom->output));
+                DPRINTF("eeprom: +++ read next address 0x%02x data=0x%04x\n",
+                    eeprom->address, eeprom->output);
 #endif
             }
             break;
@@ -613,8 +618,8 @@ static void prom9346_shift_clock(EEprom9346 *eeprom)
             eeprom->input = (eeprom->input << 1) | (bit & 1);
             if (eeprom->tick == 16)
             {
-                DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n",
-                       eeprom->address, eeprom->input));
+                DPRINTF("eeprom write to address 0x%02x data=0x%04x\n",
+                    eeprom->address, eeprom->input);
 
                 eeprom->contents[eeprom->address] = eeprom->input;
                 eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
@@ -632,8 +637,7 @@ static void prom9346_shift_clock(EEprom9346 *eeprom)
                 {
                     eeprom->contents[i] = eeprom->input;
                 }
-                DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n",
-                       eeprom->input));
+                DPRINTF("eeprom filled with data=0x%04x\n", eeprom->input);
 
                 eeprom->mode = Chip9346_enter_command_mode;
                 eeprom->tick = 0;
@@ -666,8 +670,8 @@ static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
     eeprom->eesk = eesk;
     eeprom->eedi = eedi;
 
-    DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n",
-                 eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo));
+    DPRINTF("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs,
+        eeprom->eesk, eeprom->eedi, eeprom->eedo);
 
     if (!old_eecs && eecs)
     {
@@ -677,12 +681,12 @@ static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
         eeprom->output = 0;
         eeprom->mode = Chip9346_enter_command_mode;
 
-        DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n"));
+        DPRINTF("=== eeprom: begin access, enter command mode\n");
     }
 
     if (!eecs)
     {
-        DEBUG_PRINT(("=== eeprom: end access\n"));
+        DPRINTF("=== eeprom: end access\n");
         return;
     }
 
@@ -698,8 +702,8 @@ static void rtl8139_update_irq(RTL8139State *s)
     int isr;
     isr = (s->IntrStatus & s->IntrMask) & 0xffff;
 
-    DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n",
-       isr ? 1 : 0, s->IntrStatus, s->IntrMask));
+    DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus,
+        s->IntrMask);
 
     qemu_set_irq(s->dev.irq[0], (isr != 0));
 }
@@ -763,7 +767,7 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
         /* write packet data */
         if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s)))
         {
-            DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped));
+            DPRINTF(">>> rx packet wrapped in buffer at %d\n", size - wrapped);
 
             if (size > wrapped)
             {
@@ -834,12 +838,12 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
     static const uint8_t broadcast_macaddr[6] =
         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-    DEBUG_PRINT((">>> RTL8139: received len=%d\n", size));
+    DPRINTF(">>> received len=%d\n", size);
 
     /* test if board clock is stopped */
     if (!s->clock_enabled)
     {
-        DEBUG_PRINT(("RTL8139: stopped ==========================\n"));
+        DPRINTF("stopped ==========================\n");
         return -1;
     }
 
@@ -847,21 +851,21 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
     if (!rtl8139_receiver_enabled(s))
     {
-        DEBUG_PRINT(("RTL8139: receiver disabled ================\n"));
+        DPRINTF("receiver disabled ================\n");
         return -1;
     }
 
     /* XXX: check this */
     if (s->RxConfig & AcceptAllPhys) {
         /* promiscuous: receive all */
-        DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n"));
+        DPRINTF(">>> packet received in promiscuous mode\n");
 
     } else {
         if (!memcmp(buf,  broadcast_macaddr, 6)) {
             /* broadcast address */
             if (!(s->RxConfig & AcceptBroadcast))
             {
-                DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n"));
+                DPRINTF(">>> broadcast packet rejected\n");
 
                 /* update tally counter */
                 ++s->tally_counters.RxERR;
@@ -871,7 +875,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
             packet_header |= RxBroadcast;
 
-            DEBUG_PRINT((">>> RTL8139: broadcast packet received\n"));
+            DPRINTF(">>> broadcast packet received\n");
 
             /* update tally counter */
             ++s->tally_counters.RxOkBrd;
@@ -880,7 +884,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
             /* multicast */
             if (!(s->RxConfig & AcceptMulticast))
             {
-                DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n"));
+                DPRINTF(">>> multicast packet rejected\n");
 
                 /* update tally counter */
                 ++s->tally_counters.RxERR;
@@ -892,7 +896,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
             if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
             {
-                DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n"));
+                DPRINTF(">>> multicast address mismatch\n");
 
                 /* update tally counter */
                 ++s->tally_counters.RxERR;
@@ -902,7 +906,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
             packet_header |= RxMulticast;
 
-            DEBUG_PRINT((">>> RTL8139: multicast packet received\n"));
+            DPRINTF(">>> multicast packet received\n");
 
             /* update tally counter */
             ++s->tally_counters.RxOkMul;
@@ -916,7 +920,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
             /* match */
             if (!(s->RxConfig & AcceptMyPhys))
             {
-                DEBUG_PRINT((">>> RTL8139: rejecting physical address matching packet\n"));
+                DPRINTF(">>> rejecting physical address matching packet\n");
 
                 /* update tally counter */
                 ++s->tally_counters.RxERR;
@@ -926,14 +930,14 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
             packet_header |= RxPhysical;
 
-            DEBUG_PRINT((">>> RTL8139: physical address matching packet received\n"));
+            DPRINTF(">>> physical address matching packet received\n");
 
             /* update tally counter */
             ++s->tally_counters.RxOkPhy;
 
         } else {
 
-            DEBUG_PRINT((">>> RTL8139: unknown packet\n"));
+            DPRINTF(">>> unknown packet\n");
 
             /* update tally counter */
             ++s->tally_counters.RxERR;
@@ -955,7 +959,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
     if (rtl8139_cp_receiver_enabled(s))
     {
-        DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n"));
+        DPRINTF("in C+ Rx mode ================\n");
 
         /* begin C+ receiver mode */
 
@@ -978,8 +982,9 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
         cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
         cplus_rx_ring_desc += 16 * descriptor;
 
-        DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = %016" PRIx64 "\n",
-               descriptor, s->RxRingAddrHI, s->RxRingAddrLO, (uint64_t)cplus_rx_ring_desc));
+        DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at "
+            "%08x %08x = "TARGET_FMT_plx"\n", descriptor, s->RxRingAddrHI,
+            s->RxRingAddrLO, cplus_rx_ring_desc);
 
         uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
 
@@ -992,13 +997,13 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
         cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4);
         rxbufHI = le32_to_cpu(val);
 
-        DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
-               descriptor,
-               rxdw0, rxdw1, rxbufLO, rxbufHI));
+        DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
+            descriptor, rxdw0, rxdw1, rxbufLO, rxbufHI);
 
         if (!(rxdw0 & CP_RX_OWN))
         {
-            DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor));
+            DPRINTF("C+ Rx mode : descriptor %d is owned by host\n",
+                descriptor);
 
             s->IntrStatus |= RxOverflow;
             ++s->RxMissed;
@@ -1028,9 +1033,8 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
             rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
                 &dot1q_buf[ETHER_TYPE_LEN]);
 
-            DEBUG_PRINT(("RTL8139: C+ Rx mode : extracted vlan tag with tci: "
-                    "%u\n", be16_to_cpup((uint16_t *)
-                        &dot1q_buf[ETHER_TYPE_LEN])));
+            DPRINTF("C+ Rx mode : extracted vlan tag with tci: ""%u\n",
+                be16_to_cpup((uint16_t *)&dot1q_buf[ETHER_TYPE_LEN]));
         } else {
             /* reset VLAN tag flag */
             rxdw1 &= ~CP_RX_TAVA;
@@ -1040,8 +1044,8 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
         if (size+4 > rx_space)
         {
-            DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n",
-                   descriptor, rx_space, size));
+            DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n",
+                descriptor, rx_space, size);
 
             s->IntrStatus |= RxOverflow;
             ++s->RxMissed;
@@ -1136,12 +1140,12 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
             ++s->currCPlusRxDesc;
         }
 
-        DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n"));
+        DPRINTF("done C+ Rx mode ----------------\n");
 
     }
     else
     {
-        DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n"));
+        DPRINTF("in ring Rx mode ================\n");
 
         /* begin ring receiver mode */
         int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize);
@@ -1150,8 +1154,9 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
         if (avail != 0 && size + 8 >= avail)
         {
-            DEBUG_PRINT(("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n",
-                   s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8));
+            DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
+                "read 0x%04x === available 0x%04x need 0x%04x\n",
+                s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8);
 
             s->IntrStatus |= RxOverflow;
             ++s->RxMissed;
@@ -1179,8 +1184,8 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
         /* now we can signal we have received something */
 
-        DEBUG_PRINT(("   received: rx buffer length %d head 0x%04x read 0x%04x\n",
-               s->RxBufferSize, s->RxBufAddr, s->RxBufPtr));
+        DPRINTF("received: rx buffer length %d head 0x%04x read 0x%04x\n",
+            s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
     }
 
     s->IntrStatus |= RxOK;
@@ -1374,22 +1379,22 @@ static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xff;
 
-    DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val));
+    DPRINTF("ChipCmd write val=0x%08x\n", val);
 
     if (val & CmdReset)
     {
-        DEBUG_PRINT(("RTL8139: ChipCmd reset\n"));
+        DPRINTF("ChipCmd reset\n");
         rtl8139_reset(&s->dev.qdev);
     }
     if (val & CmdRxEnb)
     {
-        DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n"));
+        DPRINTF("ChipCmd enable receiver\n");
 
         s->currCPlusRxDesc = 0;
     }
     if (val & CmdTxEnb)
     {
-        DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n"));
+        DPRINTF("ChipCmd enable transmitter\n");
 
         s->currCPlusTxDesc = 0;
     }
@@ -1409,11 +1414,11 @@ static int rtl8139_RxBufferEmpty(RTL8139State *s)
 
     if (unread != 0)
     {
-        DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", unread));
+        DPRINTF("receiver buffer data available 0x%04x\n", unread);
         return 0;
     }
 
-    DEBUG_PRINT(("RTL8139: receiver buffer is empty\n"));
+    DPRINTF("receiver buffer is empty\n");
 
     return 1;
 }
@@ -1425,7 +1430,7 @@ static uint32_t rtl8139_ChipCmd_read(RTL8139State *s)
     if (rtl8139_RxBufferEmpty(s))
         ret |= RxBufEmpty;
 
-    DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret));
+    DPRINTF("ChipCmd read val=0x%04x\n", ret);
 
     return ret;
 }
@@ -1434,7 +1439,7 @@ static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xffff;
 
-    DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val));
+    DPRINTF("C+ command register write(w) val=0x%04x\n", val);
 
     s->cplus_enabled = 1;
 
@@ -1448,21 +1453,21 @@ static uint32_t rtl8139_CpCmd_read(RTL8139State *s)
 {
     uint32_t ret = s->CpCmd;
 
-    DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret));
+    DPRINTF("C+ command register read(w) val=0x%04x\n", ret);
 
     return ret;
 }
 
 static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", val));
+    DPRINTF("C+ IntrMitigate register write(w) val=0x%04x\n", val);
 }
 
 static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
 {
     uint32_t ret = 0;
 
-    DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret));
+    DPRINTF("C+ IntrMitigate register read(w) val=0x%04x\n", ret);
 
     return ret;
 }
@@ -1474,7 +1479,7 @@ static int rtl8139_config_writeable(RTL8139State *s)
         return 1;
     }
 
-    DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n"));
+    DPRINTF("Configuration registers are write-protected\n");
 
     return 0;
 }
@@ -1483,7 +1488,7 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xffff;
 
-    DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val));
+    DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val);
 
     /* mask unwriteable bits */
     uint32_t mask = 0x4cff;
@@ -1505,7 +1510,7 @@ static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s)
 {
     uint32_t ret = s->BasicModeCtrl;
 
-    DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret));
+    DPRINTF("BasicModeCtrl register read(w) val=0x%04x\n", ret);
 
     return ret;
 }
@@ -1514,7 +1519,7 @@ static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xffff;
 
-    DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val));
+    DPRINTF("BasicModeStatus register write(w) val=0x%04x\n", val);
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
@@ -1526,7 +1531,7 @@ static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s)
 {
     uint32_t ret = s->BasicModeStatus;
 
-    DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret));
+    DPRINTF("BasicModeStatus register read(w) val=0x%04x\n", ret);
 
     return ret;
 }
@@ -1535,7 +1540,7 @@ static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xff;
 
-    DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val));
+    DPRINTF("Cfg9346 write val=0x%02x\n", val);
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0x31, s->Cfg9346);
@@ -1578,7 +1583,7 @@ static uint32_t rtl8139_Cfg9346_read(RTL8139State *s)
         }
     }
 
-    DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret));
+    DPRINTF("Cfg9346 read val=0x%02x\n", ret);
 
     return ret;
 }
@@ -1587,7 +1592,7 @@ static void rtl8139_Config0_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xff;
 
-    DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val));
+    DPRINTF("Config0 write val=0x%02x\n", val);
 
     if (!rtl8139_config_writeable(s))
         return;
@@ -1602,7 +1607,7 @@ static uint32_t rtl8139_Config0_read(RTL8139State *s)
 {
     uint32_t ret = s->Config0;
 
-    DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret));
+    DPRINTF("Config0 read val=0x%02x\n", ret);
 
     return ret;
 }
@@ -1611,7 +1616,7 @@ static void rtl8139_Config1_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xff;
 
-    DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val));
+    DPRINTF("Config1 write val=0x%02x\n", val);
 
     if (!rtl8139_config_writeable(s))
         return;
@@ -1626,7 +1631,7 @@ static uint32_t rtl8139_Config1_read(RTL8139State *s)
 {
     uint32_t ret = s->Config1;
 
-    DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret));
+    DPRINTF("Config1 read val=0x%02x\n", ret);
 
     return ret;
 }
@@ -1635,7 +1640,7 @@ static void rtl8139_Config3_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xff;
 
-    DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val));
+    DPRINTF("Config3 write val=0x%02x\n", val);
 
     if (!rtl8139_config_writeable(s))
         return;
@@ -1650,7 +1655,7 @@ static uint32_t rtl8139_Config3_read(RTL8139State *s)
 {
     uint32_t ret = s->Config3;
 
-    DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret));
+    DPRINTF("Config3 read val=0x%02x\n", ret);
 
     return ret;
 }
@@ -1659,7 +1664,7 @@ static void rtl8139_Config4_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xff;
 
-    DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val));
+    DPRINTF("Config4 write val=0x%02x\n", val);
 
     if (!rtl8139_config_writeable(s))
         return;
@@ -1674,7 +1679,7 @@ static uint32_t rtl8139_Config4_read(RTL8139State *s)
 {
     uint32_t ret = s->Config4;
 
-    DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret));
+    DPRINTF("Config4 read val=0x%02x\n", ret);
 
     return ret;
 }
@@ -1683,7 +1688,7 @@ static void rtl8139_Config5_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xff;
 
-    DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val));
+    DPRINTF("Config5 write val=0x%02x\n", val);
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0x80, s->Config5);
@@ -1695,7 +1700,7 @@ static uint32_t rtl8139_Config5_read(RTL8139State *s)
 {
     uint32_t ret = s->Config5;
 
-    DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret));
+    DPRINTF("Config5 read val=0x%02x\n", ret);
 
     return ret;
 }
@@ -1704,11 +1709,11 @@ static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val)
 {
     if (!rtl8139_transmitter_enabled(s))
     {
-        DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val));
+        DPRINTF("transmitter disabled; no TxConfig write val=0x%08x\n", val);
         return;
     }
 
-    DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val));
+    DPRINTF("TxConfig write val=0x%08x\n", val);
 
     val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
 
@@ -1717,7 +1722,7 @@ static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val)
 
 static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139C TxConfig via write(b) val=0x%02x\n", val));
+    DPRINTF("RTL8139C TxConfig via write(b) val=0x%02x\n", val);
 
     uint32_t tc = s->TxConfig;
     tc &= 0xFFFFFF00;
@@ -1729,14 +1734,14 @@ static uint32_t rtl8139_TxConfig_read(RTL8139State *s)
 {
     uint32_t ret = s->TxConfig;
 
-    DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret));
+    DPRINTF("TxConfig read val=0x%04x\n", ret);
 
     return ret;
 }
 
 static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val));
+    DPRINTF("RxConfig write val=0x%08x\n", val);
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
@@ -1746,14 +1751,14 @@ static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
     /* reset buffer size and read/write pointers */
     rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
 
-    DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize));
+    DPRINTF("RxConfig write reset buffer size to %d\n", s->RxBufferSize);
 }
 
 static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
 {
     uint32_t ret = s->RxConfig;
 
-    DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret));
+    DPRINTF("RxConfig read val=0x%08x\n", ret);
 
     return ret;
 }
@@ -1765,7 +1770,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
 
     if (!size)
     {
-        DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n"));
+        DPRINTF("+++ empty ethernet frame\n");
         return;
     }
 
@@ -1790,7 +1795,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
             buf = buf2;
         }
 
-        DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n"));
+        DPRINTF("+++ transmit loopback mode\n");
         rtl8139_do_receive(&s->nic->nc, buf, size, do_interrupt);
 
         if (iov) {
@@ -1811,25 +1816,25 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
 {
     if (!rtl8139_transmitter_enabled(s))
     {
-        DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n",
-                     descriptor));
+        DPRINTF("+++ cannot transmit from descriptor %d: transmitter "
+            "disabled\n", descriptor);
         return 0;
     }
 
     if (s->TxStatus[descriptor] & TxHostOwns)
     {
-        DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n",
-                     descriptor, s->TxStatus[descriptor]));
+        DPRINTF("+++ cannot transmit from descriptor %d: owned by host "
+            "(%08x)\n", descriptor, s->TxStatus[descriptor]);
         return 0;
     }
 
-    DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", descriptor));
+    DPRINTF("+++ transmitting from descriptor %d\n", descriptor);
 
     int txsize = s->TxStatus[descriptor] & 0x1fff;
     uint8_t txbuffer[0x2000];
 
-    DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n",
-                 txsize, s->TxAddr[descriptor]));
+    DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
+        txsize, s->TxAddr[descriptor]);
 
     cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize);
 
@@ -1839,7 +1844,8 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
 
     rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL);
 
-    DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor));
+    DPRINTF("+++ transmitted %d bytes from descriptor %d\n", txsize,
+        descriptor);
 
     /* update interrupt */
     s->IntrStatus |= TxOK;
@@ -1939,13 +1945,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 {
     if (!rtl8139_transmitter_enabled(s))
     {
-        DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n"));
+        DPRINTF("+++ C+ mode: transmitter disabled\n");
         return 0;
     }
 
     if (!rtl8139_cp_transmitter_enabled(s))
     {
-        DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n"));
+        DPRINTF("+++ C+ mode: C+ transmitter disabled\n");
         return 0 ;
     }
 
@@ -1957,8 +1963,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
     /* Normal priority ring */
     cplus_tx_ring_desc += 16 * descriptor;
 
-    DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n",
-           descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc));
+    DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at "
+        "%08x0x%08x = 0x"TARGET_FMT_plx"\n", descriptor, s->TxAddr[1],
+        s->TxAddr[0], cplus_tx_ring_desc);
 
     uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
 
@@ -1971,9 +1978,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
     cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
     txbufHI = le32_to_cpu(val);
 
-    DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n",
-           descriptor,
-           txdw0, txdw1, txbufLO, txbufHI));
+    DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor,
+        txdw0, txdw1, txbufLO, txbufHI);
 
 /* w0 ownership flag */
 #define CP_TX_OWN (1<<31)
@@ -2019,15 +2025,16 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
     if (!(txdw0 & CP_TX_OWN))
     {
-        DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor));
+        DPRINTF("C+ Tx mode : descriptor %d is owned by host\n", descriptor);
         return 0 ;
     }
 
-    DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor));
+    DPRINTF("+++ C+ Tx mode : transmitting from descriptor %d\n", descriptor);
 
     if (txdw0 & CP_TX_FS)
     {
-        DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is first segment descriptor\n", descriptor));
+        DPRINTF("+++ C+ Tx mode : descriptor %d is first segment "
+            "descriptor\n", descriptor);
 
         /* reset internal buffer offset */
         s->cplus_txbuffer_offset = 0;
@@ -2043,7 +2050,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
         s->cplus_txbuffer = qemu_malloc(s->cplus_txbuffer_len);
         s->cplus_txbuffer_offset = 0;
 
-        DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len));
+        DPRINTF("+++ C+ mode transmission buffer allocated space %d\n",
+            s->cplus_txbuffer_len);
     }
 
     while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
@@ -2051,14 +2059,16 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
         s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
         s->cplus_txbuffer = qemu_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
 
-        DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len));
+        DPRINTF("+++ C+ mode transmission buffer space changed to %d\n",
+            s->cplus_txbuffer_len);
     }
 
     if (!s->cplus_txbuffer)
     {
         /* out of memory */
 
-        DEBUG_PRINT(("RTL8139: +++ C+ mode transmiter failed to reallocate %d bytes\n", s->cplus_txbuffer_len));
+        DPRINTF("+++ C+ mode transmiter failed to reallocate %d bytes\n",
+            s->cplus_txbuffer_len);
 
         /* update tally counter */
         ++s->tally_counters.TxERR;
@@ -2069,8 +2079,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
     /* append more data to the packet */
 
-    DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at %016" PRIx64 " to offset %d\n",
-                 txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset));
+    DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at "
+        TARGET_FMT_plx" to offset %d\n", txsize, tx_addr,
+        s->cplus_txbuffer_offset);
 
     cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
     s->cplus_txbuffer_offset += txsize;
@@ -2107,7 +2118,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
         uint8_t dot1q_buffer_space[VLAN_HLEN];
         uint16_t *dot1q_buffer;
 
-        DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor));
+        DPRINTF("+++ C+ Tx mode : descriptor %d is last segment descriptor\n",
+            descriptor);
 
         /* can transfer fully assembled packet */
 
@@ -2119,8 +2131,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
         if (txdw1 & CP_TX_TAGC) {
             /* the vlan tag is in BE byte order in the descriptor
              * BE + le_to_cpu() + ~swap()~ = cpu */
-            DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : inserting vlan tag with "
-                    "tci: %u\n", bswap16(txdw1 & CP_TX_VLAN_TAG_MASK)));
+            DPRINTF("+++ C+ Tx mode : inserting vlan tag with ""tci: %u\n",
+                bswap16(txdw1 & CP_TX_VLAN_TAG_MASK));
 
             dot1q_buffer = (uint16_t *) dot1q_buffer_space;
             dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q);
@@ -2137,7 +2149,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
         if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
         {
-            DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n"));
+            DPRINTF("+++ C+ mode offloaded task checksum\n");
 
             /* ip packet header */
             ip_header *ip = NULL;
@@ -2151,7 +2163,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
             int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
             if (proto == ETH_P_IP)
             {
-                DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n"));
+                DPRINTF("+++ C+ mode has IP packet\n");
 
                 /* not aligned */
                 eth_payload_data = saved_buffer + ETH_HLEN;
@@ -2160,7 +2172,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                 ip = (ip_header*)eth_payload_data;
 
                 if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
-                    DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4));
+                    DPRINTF("+++ C+ mode packet has bad IP version %d "
+                        "expected %d\n", IP_HEADER_VERSION(ip),
+                        IP_HEADER_VERSION_4);
                     ip = NULL;
                 } else {
                     hlen = IP_HEADER_LENGTH(ip);
@@ -2173,7 +2187,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
             {
                 if (txdw0 & CP_TX_IPCS)
                 {
-                    DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n"));
+                    DPRINTF("+++ C+ mode need IP checksum\n");
 
                     if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
                         /* bad packet header len */
@@ -2183,17 +2197,18 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                     {
                         ip->ip_sum = 0;
                         ip->ip_sum = ip_checksum(ip, hlen);
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum));
+                        DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
+                            hlen, ip->ip_sum);
                     }
                 }
 
                 if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
                 {
-#if defined (DEBUG_RTL8139)
                     int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
-#endif
-                    DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n",
-                                 ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss));
+
+                    DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
+                        "frame data %d specified MSS=%d\n", ETH_MTU,
+                        ip_data_len, saved_size - ETH_HLEN, large_send_mss);
 
                     int tcp_send_offset = 0;
                     int send_count = 0;
@@ -2217,8 +2232,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                     int tcp_data_len = ip_data_len - tcp_hlen;
                     int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
 
-                    DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n",
-                                 ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size));
+                    DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
+                        "data len %d TCP chunk size %d\n", ip_data_len,
+                        tcp_hlen, tcp_data_len, tcp_chunk_size);
 
                     /* note the cycle below overwrites IP header data,
                        but restores it from saved_ip_header before sending packet */
@@ -2236,13 +2252,16 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                             chunk_size = tcp_data_len - tcp_send_offset;
                         }
 
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq)));
+                        DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
+                            be32_to_cpu(p_tcp_hdr->th_seq));
 
                         /* add 4 TCP pseudoheader fields */
                         /* copy IP source and destination fields */
                         memcpy(data_to_checksum, saved_ip_header + 12, 8);
 
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size));
+                        DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
+                            "packet with %d bytes data\n", tcp_hlen +
+                            chunk_size);
 
                         if (tcp_send_offset)
                         {
@@ -2264,7 +2283,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                         p_tcp_hdr->th_sum = 0;
 
                         int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum));
+                        DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
+                            tcp_checksum);
 
                         p_tcp_hdr->th_sum = tcp_checksum;
 
@@ -2279,10 +2299,12 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
                         ip->ip_sum = 0;
                         ip->ip_sum = ip_checksum(eth_payload_data, hlen);
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum));
+                        DPRINTF("+++ C+ mode TSO IP header len=%d "
+                            "checksum=%04x\n", hlen, ip->ip_sum);
 
                         int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size));
+                        DPRINTF("+++ C+ mode TSO transferring packet size "
+                            "%d\n", tso_send_size);
                         rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
                             0, (uint8_t *) dot1q_buffer);
 
@@ -2296,7 +2318,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                 }
                 else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
                 {
-                    DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n"));
+                    DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
 
                     /* maximum IP header length is 60 bytes */
                     uint8_t saved_ip_header[60];
@@ -2311,7 +2333,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
                     if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
                     {
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len));
+                        DPRINTF("+++ C+ mode calculating TCP checksum for "
+                            "packet with %d bytes data\n", ip_data_len);
 
                         ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
                         p_tcpip_hdr->zeros      = 0;
@@ -2323,13 +2346,15 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                         p_tcp_hdr->th_sum = 0;
 
                         int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum));
+                        DPRINTF("+++ C+ mode TCP checksum %04x\n",
+                            tcp_checksum);
 
                         p_tcp_hdr->th_sum = tcp_checksum;
                     }
                     else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
                     {
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len));
+                        DPRINTF("+++ C+ mode calculating UDP checksum for "
+                            "packet with %d bytes data\n", ip_data_len);
 
                         ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
                         p_udpip_hdr->zeros      = 0;
@@ -2341,7 +2366,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                         p_udp_hdr->uh_sum = 0;
 
                         int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
-                        DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum));
+                        DPRINTF("+++ C+ mode UDP checksum %04x\n",
+                            udp_checksum);
 
                         p_udp_hdr->uh_sum = udp_checksum;
                     }
@@ -2355,7 +2381,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
         /* update tally counter */
         ++s->tally_counters.TxOk;
 
-        DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size));
+        DPRINTF("+++ C+ mode transmitting %d bytes packet\n", saved_size);
 
         rtl8139_transfer_frame(s, saved_buffer, saved_size, 1,
             (uint8_t *) dot1q_buffer);
@@ -2374,7 +2400,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
     }
     else
     {
-        DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n"));
+        DPRINTF("+++ C+ mode transmission continue to next descriptor\n");
     }
 
     return 1;
@@ -2392,8 +2418,8 @@ static void rtl8139_cplus_transmit(RTL8139State *s)
     /* Mark transfer completed */
     if (!txcount)
     {
-        DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n",
-                     s->currCPlusTxDesc));
+        DPRINTF("C+ mode : transmitter queue stalled, current TxDesc = %d\n",
+            s->currCPlusTxDesc);
     }
     else
     {
@@ -2418,7 +2444,8 @@ static void rtl8139_transmit(RTL8139State *s)
     /* Mark transfer completed */
     if (!txcount)
     {
-        DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc));
+        DPRINTF("transmitter queue stalled, current TxDesc = %d\n",
+            s->currTxDesc);
     }
 }
 
@@ -2431,7 +2458,8 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32
 
     if (s->cplus_enabled)
     {
-        DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor));
+        DPRINTF("RTL8139C+ DTCCR write offset=0x%x val=0x%08x "
+            "descriptor=%d\n", txRegOffset, val, descriptor);
 
         /* handle Dump Tally Counters command */
         s->TxStatus[descriptor] = val;
@@ -2450,7 +2478,8 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32
         return;
     }
 
-    DEBUG_PRINT(("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor));
+    DPRINTF("TxStatus write offset=0x%x val=0x%08x descriptor=%d\n",
+        txRegOffset, val, descriptor);
 
     /* mask only reserved bits */
     val &= ~0xff00c000; /* these bits are reset on write */
@@ -2466,7 +2495,7 @@ static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset)
 {
     uint32_t ret = s->TxStatus[txRegOffset/4];
 
-    DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret));
+    DPRINTF("TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret);
 
     return ret;
 }
@@ -2498,7 +2527,7 @@ static uint16_t rtl8139_TSAD_read(RTL8139State *s)
          |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
 
 
-    DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret));
+    DPRINTF("TSAD read val=0x%04x\n", ret);
 
     return ret;
 }
@@ -2507,14 +2536,14 @@ static uint16_t rtl8139_CSCR_read(RTL8139State *s)
 {
     uint16_t ret = s->CSCR;
 
-    DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret));
+    DPRINTF("CSCR read val=0x%04x\n", ret);
 
     return ret;
 }
 
 static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val));
+    DPRINTF("TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val);
 
     s->TxAddr[txAddrOffset/4] = val;
 }
@@ -2523,20 +2552,20 @@ static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
 {
     uint32_t ret = s->TxAddr[txAddrOffset/4];
 
-    DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret));
+    DPRINTF("TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret);
 
     return ret;
 }
 
 static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val));
+    DPRINTF("RxBufPtr write val=0x%04x\n", val);
 
     /* this value is off by 16 */
     s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
 
-    DEBUG_PRINT((" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
-           s->RxBufferSize, s->RxBufAddr, s->RxBufPtr));
+    DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
+        s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
 }
 
 static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
@@ -2544,7 +2573,7 @@ static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
     /* this value is off by 16 */
     uint32_t ret = s->RxBufPtr - 0x10;
 
-    DEBUG_PRINT(("RTL8139: RxBufPtr read val=0x%04x\n", ret));
+    DPRINTF("RxBufPtr read val=0x%04x\n", ret);
 
     return ret;
 }
@@ -2554,14 +2583,14 @@ static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s)
     /* this value is NOT off by 16 */
     uint32_t ret = s->RxBufAddr;
 
-    DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret));
+    DPRINTF("RxBufAddr read val=0x%04x\n", ret);
 
     return ret;
 }
 
 static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val));
+    DPRINTF("RxBuf write val=0x%08x\n", val);
 
     s->RxBuf = val;
 
@@ -2572,14 +2601,14 @@ static uint32_t rtl8139_RxBuf_read(RTL8139State *s)
 {
     uint32_t ret = s->RxBuf;
 
-    DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret));
+    DPRINTF("RxBuf read val=0x%08x\n", ret);
 
     return ret;
 }
 
 static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val));
+    DPRINTF("IntrMask write(w) val=0x%04x\n", val);
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0x1e00, s->IntrMask);
@@ -2595,14 +2624,14 @@ static uint32_t rtl8139_IntrMask_read(RTL8139State *s)
 {
     uint32_t ret = s->IntrMask;
 
-    DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret));
+    DPRINTF("IntrMask read(w) val=0x%04x\n", ret);
 
     return ret;
 }
 
 static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val));
+    DPRINTF("IntrStatus write(w) val=0x%04x\n", val);
 
 #if 0
 
@@ -2639,7 +2668,7 @@ static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
 
     uint32_t ret = s->IntrStatus;
 
-    DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret));
+    DPRINTF("IntrStatus read(w) val=0x%04x\n", ret);
 
 #if 0
 
@@ -2655,7 +2684,7 @@ static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
 
 static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
 {
-    DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val));
+    DPRINTF("MultiIntr write(w) val=0x%04x\n", val);
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0xf000, s->MultiIntr);
@@ -2667,7 +2696,7 @@ static uint32_t rtl8139_MultiIntr_read(RTL8139State *s)
 {
     uint32_t ret = s->MultiIntr;
 
-    DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret));
+    DPRINTF("MultiIntr read(w) val=0x%04x\n", ret);
 
     return ret;
 }
@@ -2715,11 +2744,12 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
             break;
         case MediaStatus:
             /* ignore */
-            DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val));
+            DPRINTF("not implemented write(b) to MediaStatus val=0x%02x\n",
+                val);
             break;
 
         case HltClk:
-            DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val));
+            DPRINTF("HltClk write val=0x%08x\n", val);
             if (val == 'R')
             {
                 s->clock_enabled = 1;
@@ -2731,27 +2761,29 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
             break;
 
         case TxThresh:
-            DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val));
+            DPRINTF("C+ TxThresh write(b) val=0x%02x\n", val);
             s->TxThresh = val;
             break;
 
         case TxPoll:
-            DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val));
+            DPRINTF("C+ TxPoll write(b) val=0x%02x\n", val);
             if (val & (1 << 7))
             {
-                DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not implemented)\n"));
+                DPRINTF("C+ TxPoll high priority transmission (not "
+                    "implemented)\n");
                 //rtl8139_cplus_transmit(s);
             }
             if (val & (1 << 6))
             {
-                DEBUG_PRINT(("RTL8139C+ TxPoll normal priority transmission\n"));
+                DPRINTF("C+ TxPoll normal priority transmission\n");
                 rtl8139_cplus_transmit(s);
             }
 
             break;
 
         default:
-            DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val));
+            DPRINTF("not implemented write(b) addr=0x%x val=0x%02x\n", addr,
+                val);
             break;
     }
 }
@@ -2787,14 +2819,14 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
             rtl8139_BasicModeStatus_write(s, val);
             break;
         case NWayAdvert:
-            DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val));
+            DPRINTF("NWayAdvert write(w) val=0x%04x\n", val);
             s->NWayAdvert = val;
             break;
         case NWayLPAR:
-            DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val));
+            DPRINTF("forbidden NWayLPAR write(w) val=0x%04x\n", val);
             break;
         case NWayExpansion:
-            DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val));
+            DPRINTF("NWayExpansion write(w) val=0x%04x\n", val);
             s->NWayExpansion = val;
             break;
 
@@ -2807,7 +2839,8 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
             break;
 
         default:
-            DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val));
+            DPRINTF("ioport write(w) addr=0x%x val=0x%04x via write(b)\n",
+                addr, val);
 
             rtl8139_io_writeb(opaque, addr, val & 0xff);
             rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
@@ -2820,7 +2853,7 @@ static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time)
     int64_t pci_time, next_time;
     uint32_t low_pci;
 
-    DEBUG_PRINT(("RTL8139: entered rtl8139_set_next_tctr_time\n"));
+    DPRINTF("entered rtl8139_set_next_tctr_time\n");
 
     if (s->TimerExpire && current_time >= s->TimerExpire) {
         s->IntrStatus |= PCSTimeout;
@@ -2864,7 +2897,7 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
     switch (addr)
     {
         case RxMissed:
-            DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n"));
+            DPRINTF("RxMissed clearing on write\n");
             s->RxMissed = 0;
             break;
 
@@ -2889,23 +2922,23 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
             break;
 
         case RxRingAddrLO:
-            DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", val));
+            DPRINTF("C+ RxRing low bits write val=0x%08x\n", val);
             s->RxRingAddrLO = val;
             break;
 
         case RxRingAddrHI:
-            DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", val));
+            DPRINTF("C+ RxRing high bits write val=0x%08x\n", val);
             s->RxRingAddrHI = val;
             break;
 
         case Timer:
-            DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n"));
+            DPRINTF("TCTR Timer reset on write\n");
             s->TCTR_base = qemu_get_clock_ns(vm_clock);
             rtl8139_set_next_tctr_time(s, s->TCTR_base);
             break;
 
         case FlashReg:
-            DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val));
+            DPRINTF("FlashReg TimerInt write val=0x%08x\n", val);
             if (s->TimerInt != val) {
                 s->TimerInt = val;
                 rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
@@ -2913,7 +2946,8 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
             break;
 
         default:
-            DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val));
+            DPRINTF("ioport write(l) addr=0x%x val=0x%08x via write(b)\n",
+                addr, val);
             rtl8139_io_writeb(opaque, addr, val & 0xff);
             rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
             rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff);
@@ -2964,31 +2998,31 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
 
         case MediaStatus:
             ret = 0xd0;
-            DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret));
+            DPRINTF("MediaStatus read 0x%x\n", ret);
             break;
 
         case HltClk:
             ret = s->clock_enabled;
-            DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret));
+            DPRINTF("HltClk read 0x%x\n", ret);
             break;
 
         case PCIRevisionID:
             ret = RTL8139_PCI_REVID;
-            DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret));
+            DPRINTF("PCI Revision ID read 0x%x\n", ret);
             break;
 
         case TxThresh:
             ret = s->TxThresh;
-            DEBUG_PRINT(("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret));
+            DPRINTF("C+ TxThresh read(b) val=0x%02x\n", ret);
             break;
 
         case 0x43: /* Part of TxConfig register. Windows driver tries to read it */
             ret = s->TxConfig >> 24;
-            DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret));
+            DPRINTF("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret);
             break;
 
         default:
-            DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", addr));
+            DPRINTF("not implemented read(b) addr=0x%x\n", addr);
             ret = 0;
             break;
     }
@@ -3033,15 +3067,15 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
             break;
         case NWayAdvert:
             ret = s->NWayAdvert;
-            DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret));
+            DPRINTF("NWayAdvert read(w) val=0x%04x\n", ret);
             break;
         case NWayLPAR:
             ret = s->NWayLPAR;
-            DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret));
+            DPRINTF("NWayLPAR read(w) val=0x%04x\n", ret);
             break;
         case NWayExpansion:
             ret = s->NWayExpansion;
-            DEBUG_PRINT(("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret));
+            DPRINTF("NWayExpansion read(w) val=0x%04x\n", ret);
             break;
 
         case CpCmd:
@@ -3061,12 +3095,12 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
             break;
 
         default:
-            DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr));
+            DPRINTF("ioport read(w) addr=0x%x via read(b)\n", addr);
 
             ret  = rtl8139_io_readb(opaque, addr);
             ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
 
-            DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret));
+            DPRINTF("ioport read(w) addr=0x%x val=0x%04x\n", addr, ret);
             break;
     }
 
@@ -3085,7 +3119,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
         case RxMissed:
             ret = s->RxMissed;
 
-            DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret));
+            DPRINTF("RxMissed read val=0x%08x\n", ret);
             break;
 
         case TxConfig:
@@ -3110,34 +3144,34 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
 
         case RxRingAddrLO:
             ret = s->RxRingAddrLO;
-            DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret));
+            DPRINTF("C+ RxRing low bits read val=0x%08x\n", ret);
             break;
 
         case RxRingAddrHI:
             ret = s->RxRingAddrHI;
-            DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret));
+            DPRINTF("C+ RxRing high bits read val=0x%08x\n", ret);
             break;
 
         case Timer:
             ret = muldiv64(qemu_get_clock_ns(vm_clock) - s->TCTR_base,
                            PCI_FREQUENCY, get_ticks_per_sec());
-            DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret));
+            DPRINTF("TCTR Timer read val=0x%08x\n", ret);
             break;
 
         case FlashReg:
             ret = s->TimerInt;
-            DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret));
+            DPRINTF("FlashReg TimerInt read val=0x%08x\n", ret);
             break;
 
         default:
-            DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr));
+            DPRINTF("ioport read(l) addr=0x%x via read(b)\n", addr);
 
             ret  = rtl8139_io_readb(opaque, addr);
             ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
             ret |= rtl8139_io_readb(opaque, addr + 2) << 16;
             ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
 
-            DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret));
+            DPRINTF("read(l) addr=0x%x val=%08x\n", addr, ret);
             break;
     }
 
@@ -3374,7 +3408,7 @@ static void rtl8139_timer(void *opaque)
 
     if (!s->clock_enabled)
     {
-        DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n"));
+        DPRINTF(">>> timer: clock is not running\n");
         return;
     }
 
@@ -3475,7 +3509,7 @@ static PCIDeviceInfo rtl8139_info = {
     .qdev.vmsd  = &vmstate_rtl8139,
     .init       = pci_rtl8139_init,
     .exit       = pci_rtl8139_uninit,
-    .romfile    = "pxe-rtl8139.bin",
+    .romfile    = "pxe-rtl8139.rom",
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(RTL8139State, conf),
         DEFINE_PROP_END_OF_LIST(),
index 784dc01b97d2e5a7f7fc48e8b4967cbc81e94b3c..bb49e393ec8bdfa0c2e5447606a58abd1edf5c4b 100644 (file)
@@ -43,6 +43,8 @@
     do { } while (0)
 #endif
 
+#define VIRTIO_EXT_CODE   0x2603
+
 struct BusInfo s390_virtio_bus_info = {
     .name       = "s390-virtio",
     .size       = sizeof(VirtIOS390Bus),
@@ -139,7 +141,7 @@ static int s390_virtio_serial_init(VirtIOS390Device *dev)
 
     bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus);
 
-    vdev = virtio_serial_init((DeviceState *)dev, dev->max_virtserial_ports);
+    vdev = virtio_serial_init((DeviceState *)dev, &dev->serial);
     if (!vdev) {
         return -1;
     }
@@ -223,7 +225,7 @@ void s390_virtio_device_sync(VirtIOS390Device *dev)
     cur_offs += num_vq * VIRTIO_VQCONFIG_LEN;
 
     /* Sync feature bitmap */
-    stl_phys(cur_offs, dev->host_features);
+    stl_phys(cur_offs, bswap32(dev->host_features));
 
     dev->feat_offs = cur_offs + dev->feat_len;
     cur_offs += dev->feat_len * 2;
@@ -233,7 +235,8 @@ void s390_virtio_device_sync(VirtIOS390Device *dev)
         dev->vdev->get_config(dev->vdev, dev->vdev->config);
     }
 
-    cpu_physical_memory_rw(cur_offs, dev->vdev->config, dev->vdev->config_len, 1);
+    cpu_physical_memory_write(cur_offs,
+                              dev->vdev->config, dev->vdev->config_len);
     cur_offs += dev->vdev->config_len;
 }
 
@@ -246,7 +249,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
 
     /* Update guest supported feature bitmap */
 
-    features = ldl_phys(dev->feat_offs);
+    features = bswap32(ldl_phys(dev->feat_offs));
     if (vdev->set_features) {
         vdev->set_features(vdev, features);
     }
@@ -304,9 +307,13 @@ static void virtio_s390_notify(void *opaque, uint16_t vector)
 {
     VirtIOS390Device *dev = (VirtIOS390Device*)opaque;
     uint64_t token = s390_virtio_device_vq_token(dev, vector);
+    CPUState *env = s390_cpu_addr2state(0);
 
-    /* XXX kvm dependency! */
-    kvm_s390_virtio_irq(s390_cpu_addr2state(0), 0, token);
+    if (kvm_enabled()) {
+        kvm_s390_virtio_irq(env, 0, token);
+    } else {
+        cpu_inject_ext(env, VIRTIO_EXT_CODE, 0, token);
+    }
 }
 
 static unsigned virtio_s390_get_features(void *opaque)
@@ -325,6 +332,7 @@ static const VirtIOBindings virtio_s390_bindings = {
 static VirtIOS390DeviceInfo s390_virtio_net = {
     .init = s390_virtio_net_init,
     .qdev.name = "virtio-net-s390",
+    .qdev.alias = "virtio-net",
     .qdev.size = sizeof(VirtIOS390Device),
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
@@ -340,6 +348,7 @@ static VirtIOS390DeviceInfo s390_virtio_net = {
 static VirtIOS390DeviceInfo s390_virtio_blk = {
     .init = s390_virtio_blk_init,
     .qdev.name = "virtio-blk-s390",
+    .qdev.alias = "virtio-blk",
     .qdev.size = sizeof(VirtIOS390Device),
     .qdev.props = (Property[]) {
         DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
@@ -353,8 +362,8 @@ static VirtIOS390DeviceInfo s390_virtio_serial = {
     .qdev.alias = "virtio-serial",
     .qdev.size = sizeof(VirtIOS390Device),
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("max_ports", VirtIOS390Device, max_virtserial_ports,
-                           31),
+        DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
+                           serial.max_virtserial_ports, 31),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
index 33379a3ba462da678f2570997c1d6422ce56345d..edf6d045708d05a0a225e4e8fa92330ff4ac08d1 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "virtio-net.h"
+#include "virtio-serial.h"
 
 #define VIRTIO_DEV_OFFS_TYPE           0       /* 8 bits */
 #define VIRTIO_DEV_OFFS_NUM_VQ         1       /* 8 bits */
@@ -43,8 +44,7 @@ typedef struct VirtIOS390Device {
     BlockConf block;
     NICConf nic;
     uint32_t host_features;
-    /* Max. number of ports we can have for a the virtio-serial device */
-    uint32_t max_virtserial_ports;
+    virtio_serial_conf serial;
     virtio_net_conf net;
 } VirtIOS390Device;
 
index 850422fee07472ac08087dd18f33c872dff6d2d6..698ff6f34512f52133def1653b26f52f6ff773f0 100644 (file)
@@ -82,13 +82,12 @@ CPUState *s390_cpu_addr2state(uint16_t cpu_addr)
     return ipi_states[cpu_addr];
 }
 
-int s390_virtio_hypercall(CPUState *env)
+int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall)
 {
     int r = 0, i;
-    target_ulong mem = env->regs[2];
 
-    dprintf("KVM hypercall: %ld\n", env->regs[1]);
-    switch (env->regs[1]) {
+    dprintf("KVM hypercall: %ld\n", hypercall);
+    switch (hypercall) {
     case KVM_S390_VIRTIO_NOTIFY:
         if (mem > ram_size) {
             VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus,
@@ -128,8 +127,7 @@ int s390_virtio_hypercall(CPUState *env)
         break;
     }
 
-    env->regs[2] = r;
-    return 0;
+    return r;
 }
 
 /* PC hardware initialisation */
@@ -145,14 +143,9 @@ static void s390_init(ram_addr_t ram_size,
     ram_addr_t kernel_size = 0;
     ram_addr_t initrd_offset;
     ram_addr_t initrd_size = 0;
+    uint8_t *storage_keys;
     int i;
 
-    /* XXX we only work on KVM for now */
-
-    if (!kvm_enabled()) {
-        fprintf(stderr, "The S390 target only works with KVM enabled\n");
-        exit(1);
-    }
 
     /* get a BUS */
     s390_bus = s390_virtio_bus_init(&ram_size);
@@ -161,6 +154,9 @@ static void s390_init(ram_addr_t ram_size,
     ram_addr = qemu_ram_alloc(NULL, "s390.ram", ram_size);
     cpu_register_physical_memory(0, ram_size, ram_addr);
 
+    /* allocate storage keys */
+    storage_keys = qemu_mallocz(ram_size / TARGET_PAGE_SIZE);
+
     /* init CPUs */
     if (cpu_model == NULL) {
         cpu_model = "host";
@@ -178,6 +174,7 @@ static void s390_init(ram_addr_t ram_size,
         ipi_states[i] = tmp_env;
         tmp_env->halted = 1;
         tmp_env->exception_index = EXCP_HLT;
+        tmp_env->storage_keys = storage_keys;
     }
 
     env->halted = 0;
@@ -230,8 +227,8 @@ static void s390_init(ram_addr_t ram_size,
     }
 
     if (kernel_cmdline) {
-        cpu_physical_memory_rw(KERN_PARM_AREA, (uint8_t *)kernel_cmdline,
-                               strlen(kernel_cmdline), 1);
+        cpu_physical_memory_write(KERN_PARM_AREA, kernel_cmdline,
+                                  strlen(kernel_cmdline));
     }
 
     /* Create VirtIO network adapters */
index d1ceef9cb627a25e82d57465bdaabc5b0514edef..2d4a3d8b4864247641eb47c9813416a4f2c01415 100644 (file)
@@ -120,7 +120,7 @@ static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt,
 
         /* get pixel value */
         if (i % 4 == 0) {
-            cpu_physical_memory_rw(cursor_addr, &bitset, 1, 0);
+            bitset = ldub_phys(cursor_addr);
             cursor_addr++;
         }
         v = bitset & 3;
index 571c52dfb1abde7afcf4d4c3b0d2bc768ba3fbdd..a39871593b876e25ff5958bce34a3cf1531c49e1 100644 (file)
@@ -66,3 +66,6 @@ void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data
 int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data);
 void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
                        int len);
+
+void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
+                       const uint8_t *eeprom_spd, int size);
index 52463e0f8667cb6c6e07110b8693ed90b818bf21..36347548911181c2ff79b39fbb363fff55d017d7 100644 (file)
@@ -96,7 +96,7 @@ static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
     return eeprom_receive_byte(dev);
 }
 
-static int smbus_eeprom_init(SMBusDevice *dev)
+static int smbus_eeprom_initfn(SMBusDevice *dev)
 {
     SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
 
@@ -111,7 +111,7 @@ static SMBusDeviceInfo smbus_eeprom_info = {
         DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
         DEFINE_PROP_END_OF_LIST(),
     },
-    .init = smbus_eeprom_init,
+    .init = smbus_eeprom_initfn,
     .quick_cmd = eeprom_quick_cmd,
     .send_byte = eeprom_send_byte,
     .receive_byte = eeprom_receive_byte,
@@ -125,3 +125,21 @@ static void smbus_eeprom_register_devices(void)
 }
 
 device_init(smbus_eeprom_register_devices)
+
+void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
+                       const uint8_t *eeprom_spd, int eeprom_spd_size)
+{
+    int i;
+    uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+    if (eeprom_spd_size > 0) {
+        memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size);
+    }
+
+    for (i = 0; i < nb_eeprom; i++) {
+        DeviceState *eeprom;
+        eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
+        qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
+        qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
+        qdev_init_nofail(eeprom);
+    }
+}
diff --git a/hw/spapr.c b/hw/spapr.c
new file mode 100644 (file)
index 0000000..1782cc0
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#include "sysemu.h"
+#include "hw.h"
+#include "elf.h"
+#include "net.h"
+#include "blockdev.h"
+
+#include "hw/boards.h"
+#include "hw/ppc.h"
+#include "hw/loader.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+#include "hw/xics.h"
+
+#include <libfdt.h>
+
+#define KERNEL_LOAD_ADDR        0x00000000
+#define INITRD_LOAD_ADDR        0x02800000
+#define FDT_MAX_SIZE            0x10000
+#define RTAS_MAX_SIZE           0x10000
+#define FW_MAX_SIZE             0x400000
+#define FW_FILE_NAME            "slof.bin"
+
+#define MIN_RAM_SLOF           512UL
+
+#define TIMEBASE_FREQ           512000000ULL
+
+#define MAX_CPUS                32
+#define XICS_IRQS              1024
+
+sPAPREnvironment *spapr;
+
+static void *spapr_create_fdt_skel(const char *cpu_model,
+                                   target_phys_addr_t initrd_base,
+                                   target_phys_addr_t initrd_size,
+                                   const char *boot_device,
+                                   const char *kernel_cmdline,
+                                   long hash_shift)
+{
+    void *fdt;
+    CPUState *env;
+    uint64_t mem_reg_property[] = { 0, cpu_to_be64(ram_size) };
+    uint32_t start_prop = cpu_to_be32(initrd_base);
+    uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
+    uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
+    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
+        "\0hcall-tce\0hcall-vio\0hcall-splpar";
+    uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
+    int i;
+    char *modelname;
+
+#define _FDT(exp) \
+    do { \
+        int ret = (exp);                                           \
+        if (ret < 0) {                                             \
+            fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
+                    #exp, fdt_strerror(ret));                      \
+            exit(1);                                               \
+        }                                                          \
+    } while (0)
+
+    fdt = qemu_mallocz(FDT_MAX_SIZE);
+    _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
+
+    _FDT((fdt_finish_reservemap(fdt)));
+
+    /* Root node */
+    _FDT((fdt_begin_node(fdt, "")));
+    _FDT((fdt_property_string(fdt, "device_type", "chrp")));
+    _FDT((fdt_property_string(fdt, "model", "qemu,emulated-pSeries-LPAR")));
+
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
+
+    /* /chosen */
+    _FDT((fdt_begin_node(fdt, "chosen")));
+
+    _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
+    _FDT((fdt_property(fdt, "linux,initrd-start",
+                       &start_prop, sizeof(start_prop))));
+    _FDT((fdt_property(fdt, "linux,initrd-end",
+                       &end_prop, sizeof(end_prop))));
+    _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* memory node */
+    _FDT((fdt_begin_node(fdt, "memory@0")));
+
+    _FDT((fdt_property_string(fdt, "device_type", "memory")));
+    _FDT((fdt_property(fdt, "reg",
+                       mem_reg_property, sizeof(mem_reg_property))));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* cpus */
+    _FDT((fdt_begin_node(fdt, "cpus")));
+
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+
+    modelname = qemu_strdup(cpu_model);
+
+    for (i = 0; i < strlen(modelname); i++) {
+        modelname[i] = toupper(modelname[i]);
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        int index = env->cpu_index;
+        uint32_t gserver_prop[] = {cpu_to_be32(index), 0}; /* HACK! */
+        char *nodename;
+        uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
+                           0xffffffff, 0xffffffff};
+
+        if (asprintf(&nodename, "%s@%x", modelname, index) < 0) {
+            fprintf(stderr, "Allocation failure\n");
+            exit(1);
+        }
+
+        _FDT((fdt_begin_node(fdt, nodename)));
+
+        free(nodename);
+
+        _FDT((fdt_property_cell(fdt, "reg", index)));
+        _FDT((fdt_property_string(fdt, "device_type", "cpu")));
+
+        _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
+        _FDT((fdt_property_cell(fdt, "dcache-block-size",
+                                env->dcache_line_size)));
+        _FDT((fdt_property_cell(fdt, "icache-block-size",
+                                env->icache_line_size)));
+        _FDT((fdt_property_cell(fdt, "timebase-frequency", TIMEBASE_FREQ)));
+        /* Hardcode CPU frequency for now.  It's kind of arbitrary on
+         * full emu, for kvm we should copy it from the host */
+        _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000)));
+        _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
+        _FDT((fdt_property(fdt, "ibm,pft-size",
+                           pft_size_prop, sizeof(pft_size_prop))));
+        _FDT((fdt_property_string(fdt, "status", "okay")));
+        _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
+        _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", index)));
+        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
+                           gserver_prop, sizeof(gserver_prop))));
+
+        if (env->mmu_model & POWERPC_MMU_1TSEG) {
+            _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
+                               segs, sizeof(segs))));
+        }
+
+        _FDT((fdt_end_node(fdt)));
+    }
+
+    qemu_free(modelname);
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* RTAS */
+    _FDT((fdt_begin_node(fdt, "rtas")));
+
+    _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
+                       sizeof(hypertas_prop))));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* interrupt controller */
+    _FDT((fdt_begin_node(fdt, "interrupt-controller@0")));
+
+    _FDT((fdt_property_string(fdt, "device_type",
+                              "PowerPC-External-Interrupt-Presentation")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
+    _FDT((fdt_property_cell(fdt, "reg", 0)));
+    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
+    _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
+                       interrupt_server_ranges_prop,
+                       sizeof(interrupt_server_ranges_prop))));
+
+    _FDT((fdt_end_node(fdt)));
+
+    /* vdevice */
+    _FDT((fdt_begin_node(fdt, "vdevice")));
+
+    _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
+    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
+
+    _FDT((fdt_end_node(fdt)));
+
+    _FDT((fdt_end_node(fdt))); /* close root node */
+    _FDT((fdt_finish(fdt)));
+
+    return fdt;
+}
+
+static void spapr_finalize_fdt(sPAPREnvironment *spapr,
+                               target_phys_addr_t fdt_addr,
+                               target_phys_addr_t rtas_addr,
+                               target_phys_addr_t rtas_size)
+{
+    int ret;
+    void *fdt;
+
+    fdt = qemu_malloc(FDT_MAX_SIZE);
+
+    /* open out the base tree into a temp buffer for the final tweaks */
+    _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE)));
+
+    ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
+    if (ret < 0) {
+        fprintf(stderr, "couldn't setup vio devices in fdt\n");
+        exit(1);
+    }
+
+    /* RTAS */
+    ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
+    }
+
+    _FDT((fdt_pack(fdt)));
+
+    cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
+
+    qemu_free(fdt);
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
+}
+
+static void emulate_spapr_hypercall(CPUState *env)
+{
+    env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
+}
+
+static void spapr_reset(void *opaque)
+{
+    sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
+
+    fprintf(stderr, "sPAPR reset\n");
+
+    /* flush out the hash table */
+    memset(spapr->htab, 0, spapr->htab_size);
+
+    /* Load the fdt */
+    spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
+                       spapr->rtas_size);
+
+    /* Set up the entry state */
+    first_cpu->gpr[3] = spapr->fdt_addr;
+    first_cpu->gpr[5] = 0;
+    first_cpu->halted = 0;
+    first_cpu->nip = spapr->entry_point;
+
+}
+
+/* pSeries LPAR / sPAPR hardware init */
+static void ppc_spapr_init(ram_addr_t ram_size,
+                           const char *boot_device,
+                           const char *kernel_filename,
+                           const char *kernel_cmdline,
+                           const char *initrd_filename,
+                           const char *cpu_model)
+{
+    CPUState *env;
+    int i;
+    ram_addr_t ram_offset;
+    uint32_t initrd_base;
+    long kernel_size, initrd_size, fw_size;
+    long pteg_shift = 17;
+    char *filename;
+    int irq = 16;
+
+    spapr = qemu_malloc(sizeof(*spapr));
+    cpu_ppc_hypercall = emulate_spapr_hypercall;
+
+    /* We place the device tree just below either the top of RAM, or
+     * 2GB, so that it can be processed with 32-bit code if
+     * necessary */
+    spapr->fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE;
+    spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "POWER7";
+    }
+    for (i = 0; i < smp_cpus; i++) {
+        env = cpu_init(cpu_model);
+
+        if (!env) {
+            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
+            exit(1);
+        }
+        /* Set time-base frequency to 512 MHz */
+        cpu_ppc_tb_init(env, TIMEBASE_FREQ);
+        qemu_register_reset((QEMUResetHandler *)&cpu_reset, env);
+
+        env->hreset_vector = 0x60;
+        env->hreset_excp_prefix = 0;
+        env->gpr[3] = env->cpu_index;
+    }
+
+    /* allocate RAM */
+    ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+
+    /* allocate hash page table.  For now we always make this 16mb,
+     * later we should probably make it scale to the size of guest
+     * RAM */
+    spapr->htab_size = 1ULL << (pteg_shift + 7);
+    spapr->htab = qemu_malloc(spapr->htab_size);
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        env->external_htab = spapr->htab;
+        env->htab_base = -1;
+        env->htab_mask = spapr->htab_size - 1;
+    }
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
+    spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
+                                           ram_size - spapr->rtas_addr);
+    if (spapr->rtas_size < 0) {
+        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+        exit(1);
+    }
+    qemu_free(filename);
+
+    /* Set up Interrupt Controller */
+    spapr->icp = xics_system_init(XICS_IRQS);
+
+    /* Set up VIO bus */
+    spapr->vio_bus = spapr_vio_bus_init();
+
+    for (i = 0; i < MAX_SERIAL_PORTS; i++, irq++) {
+        if (serial_hds[i]) {
+            spapr_vty_create(spapr->vio_bus, i, serial_hds[i],
+                             xics_find_qirq(spapr->icp, irq), irq);
+        }
+    }
+
+    for (i = 0; i < nb_nics; i++, irq++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!nd->model) {
+            nd->model = qemu_strdup("ibmveth");
+        }
+
+        if (strcmp(nd->model, "ibmveth") == 0) {
+            spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd,
+                              xics_find_qirq(spapr->icp, irq), irq);
+        } else {
+            fprintf(stderr, "pSeries (sPAPR) platform does not support "
+                    "NIC model '%s' (only ibmveth is supported)\n",
+                    nd->model);
+            exit(1);
+        }
+    }
+
+    for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
+        spapr_vscsi_create(spapr->vio_bus, 0x2000 + i,
+                           xics_find_qirq(spapr->icp, irq), irq);
+        irq++;
+    }
+
+    if (kernel_filename) {
+        uint64_t lowaddr = 0;
+
+        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
+                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              ram_size - KERNEL_LOAD_ADDR);
+        }
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+
+        spapr->entry_point = KERNEL_LOAD_ADDR;
+    } else {
+        if (ram_size < (MIN_RAM_SLOF << 20)) {
+            fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
+                    "%ldM guest RAM\n", MIN_RAM_SLOF);
+            exit(1);
+        }
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "slof.bin");
+        fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
+        if (fw_size < 0) {
+            hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+            exit(1);
+        }
+        qemu_free(filename);
+        spapr->entry_point = 0x100;
+        initrd_base = 0;
+        initrd_size = 0;
+
+        /* SLOF will startup the secondary CPUs using RTAS,
+           rather than expecting a kexec() style entry */
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            env->halted = 1;
+        }
+    }
+
+    /* Prepare the device tree */
+    spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
+                                            initrd_base, initrd_size,
+                                            boot_device, kernel_cmdline,
+                                            pteg_shift + 7);
+    assert(spapr->fdt_skel != NULL);
+
+    qemu_register_reset(spapr_reset, spapr);
+}
+
+static QEMUMachine spapr_machine = {
+    .name = "pseries",
+    .desc = "pSeries Logical Partition (PAPR compliant)",
+    .init = ppc_spapr_init,
+    .max_cpus = MAX_CPUS,
+    .no_vga = 1,
+    .no_parallel = 1,
+    .use_scsi = 1,
+};
+
+static void spapr_machine_init(void)
+{
+    qemu_register_machine(&spapr_machine);
+}
+
+machine_init(spapr_machine_init);
diff --git a/hw/spapr.h b/hw/spapr.h
new file mode 100644 (file)
index 0000000..b52133a
--- /dev/null
@@ -0,0 +1,301 @@
+#if !defined(__HW_SPAPR_H__)
+#define __HW_SPAPR_H__
+
+struct VIOsPAPRBus;
+struct icp_state;
+
+typedef struct sPAPREnvironment {
+    struct VIOsPAPRBus *vio_bus;
+    struct icp_state *icp;
+
+    void *htab;
+    long htab_size;
+    target_phys_addr_t fdt_addr, rtas_addr;
+    long rtas_size;
+    void *fdt_skel;
+    target_ulong entry_point;
+} sPAPREnvironment;
+
+#define H_SUCCESS         0
+#define H_BUSY            1        /* Hardware busy -- retry later */
+#define H_CLOSED          2        /* Resource closed */
+#define H_NOT_AVAILABLE   3
+#define H_CONSTRAINED     4        /* Resource request constrained to max allowed */
+#define H_PARTIAL         5
+#define H_IN_PROGRESS     14       /* Kind of like busy */
+#define H_PAGE_REGISTERED 15
+#define H_PARTIAL_STORE   16
+#define H_PENDING         17       /* returned from H_POLL_PENDING */
+#define H_CONTINUE        18       /* Returned from H_Join on success */
+#define H_LONG_BUSY_START_RANGE         9900  /* Start of long busy range */
+#define H_LONG_BUSY_ORDER_1_MSEC        9900  /* Long busy, hint that 1msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_MSEC       9901  /* Long busy, hint that 10msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_MSEC      9902  /* Long busy, hint that 100msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_1_SEC         9903  /* Long busy, hint that 1sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_SEC        9904  /* Long busy, hint that 10sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_SEC       9905  /* Long busy, hint that 100sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_END_RANGE           9905  /* End of long busy range */
+#define H_HARDWARE        -1       /* Hardware error */
+#define H_FUNCTION        -2       /* Function not supported */
+#define H_PRIVILEGE       -3       /* Caller not privileged */
+#define H_PARAMETER       -4       /* Parameter invalid, out-of-range or conflicting */
+#define H_BAD_MODE        -5       /* Illegal msr value */
+#define H_PTEG_FULL       -6       /* PTEG is full */
+#define H_NOT_FOUND       -7       /* PTE was not found" */
+#define H_RESERVED_DABR   -8       /* DABR address is reserved by the hypervisor on this processor" */
+#define H_NO_MEM          -9
+#define H_AUTHORITY       -10
+#define H_PERMISSION      -11
+#define H_DROPPED         -12
+#define H_SOURCE_PARM     -13
+#define H_DEST_PARM       -14
+#define H_REMOTE_PARM     -15
+#define H_RESOURCE        -16
+#define H_ADAPTER_PARM    -17
+#define H_RH_PARM         -18
+#define H_RCQ_PARM        -19
+#define H_SCQ_PARM        -20
+#define H_EQ_PARM         -21
+#define H_RT_PARM         -22
+#define H_ST_PARM         -23
+#define H_SIGT_PARM       -24
+#define H_TOKEN_PARM      -25
+#define H_MLENGTH_PARM    -27
+#define H_MEM_PARM        -28
+#define H_MEM_ACCESS_PARM -29
+#define H_ATTR_PARM       -30
+#define H_PORT_PARM       -31
+#define H_MCG_PARM        -32
+#define H_VL_PARM         -33
+#define H_TSIZE_PARM      -34
+#define H_TRACE_PARM      -35
+
+#define H_MASK_PARM       -37
+#define H_MCG_FULL        -38
+#define H_ALIAS_EXIST     -39
+#define H_P_COUNTER       -40
+#define H_TABLE_FULL      -41
+#define H_ALT_TABLE       -42
+#define H_MR_CONDITION    -43
+#define H_NOT_ENOUGH_RESOURCES -44
+#define H_R_STATE         -45
+#define H_RESCINDEND      -46
+#define H_MULTI_THREADS_ACTIVE -9005
+
+
+/* Long Busy is a condition that can be returned by the firmware
+ * when a call cannot be completed now, but the identical call
+ * should be retried later.  This prevents calls blocking in the
+ * firmware for long periods of time.  Annoyingly the firmware can return
+ * a range of return codes, hinting at how long we should wait before
+ * retrying.  If you don't care for the hint, the macro below is a good
+ * way to check for the long_busy return codes
+ */
+#define H_IS_LONG_BUSY(x)  ((x >= H_LONG_BUSY_START_RANGE) \
+                            && (x <= H_LONG_BUSY_END_RANGE))
+
+/* Flags */
+#define H_LARGE_PAGE      (1ULL<<(63-16))
+#define H_EXACT           (1ULL<<(63-24))       /* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE         (1ULL<<(63-25))       /* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4          (1ULL<<(63-26))       /* Return 4 PTEs */
+#define H_PAGE_STATE_CHANGE (1ULL<<(63-28))
+#define H_PAGE_UNUSED     ((1ULL<<(63-29)) | (1ULL<<(63-30)))
+#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED)
+#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1ULL<<(63-31)))
+#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE
+#define H_AVPN            (1ULL<<(63-32))       /* An avpn is provided as a sanity test */
+#define H_ANDCOND         (1ULL<<(63-33))
+#define H_ICACHE_INVALIDATE (1ULL<<(63-40))     /* icbi, etc.  (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE (1ULL<<(63-41))    /* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE       (1ULL<<(63-48))       /* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE       (1ULL<<(63-49))
+#define H_N               (1ULL<<(63-61))
+#define H_PP1             (1ULL<<(63-62))
+#define H_PP2             (1ULL<<(63-63))
+
+/* VASI States */
+#define H_VASI_INVALID    0
+#define H_VASI_ENABLED    1
+#define H_VASI_ABORTED    2
+#define H_VASI_SUSPENDING 3
+#define H_VASI_SUSPENDED  4
+#define H_VASI_RESUMED    5
+#define H_VASI_COMPLETED  6
+
+/* DABRX flags */
+#define H_DABRX_HYPERVISOR (1ULL<<(63-61))
+#define H_DABRX_KERNEL     (1ULL<<(63-62))
+#define H_DABRX_USER       (1ULL<<(63-63))
+
+/* Each control block has to be on a 4K bondary */
+#define H_CB_ALIGNMENT     4096
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE                0x04
+#define H_ENTER                 0x08
+#define H_READ                  0x0c
+#define H_CLEAR_MOD             0x10
+#define H_CLEAR_REF             0x14
+#define H_PROTECT               0x18
+#define H_GET_TCE               0x1c
+#define H_PUT_TCE               0x20
+#define H_SET_SPRG0             0x24
+#define H_SET_DABR              0x28
+#define H_PAGE_INIT             0x2c
+#define H_SET_ASR               0x30
+#define H_ASR_ON                0x34
+#define H_ASR_OFF               0x38
+#define H_LOGICAL_CI_LOAD       0x3c
+#define H_LOGICAL_CI_STORE      0x40
+#define H_LOGICAL_CACHE_LOAD    0x44
+#define H_LOGICAL_CACHE_STORE   0x48
+#define H_LOGICAL_ICBI          0x4c
+#define H_LOGICAL_DCBF          0x50
+#define H_GET_TERM_CHAR         0x54
+#define H_PUT_TERM_CHAR         0x58
+#define H_REAL_TO_LOGICAL       0x5c
+#define H_HYPERVISOR_DATA       0x60
+#define H_EOI                   0x64
+#define H_CPPR                  0x68
+#define H_IPI                   0x6c
+#define H_IPOLL                 0x70
+#define H_XIRR                  0x74
+#define H_PERFMON               0x7c
+#define H_MIGRATE_DMA           0x78
+#define H_REGISTER_VPA          0xDC
+#define H_CEDE                  0xE0
+#define H_CONFER                0xE4
+#define H_PROD                  0xE8
+#define H_GET_PPP               0xEC
+#define H_SET_PPP               0xF0
+#define H_PURR                  0xF4
+#define H_PIC                   0xF8
+#define H_REG_CRQ               0xFC
+#define H_FREE_CRQ              0x100
+#define H_VIO_SIGNAL            0x104
+#define H_SEND_CRQ              0x108
+#define H_COPY_RDMA             0x110
+#define H_REGISTER_LOGICAL_LAN  0x114
+#define H_FREE_LOGICAL_LAN      0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN      0x120
+#define H_BULK_REMOVE           0x124
+#define H_MULTICAST_CTRL        0x130
+#define H_SET_XDABR             0x134
+#define H_STUFF_TCE             0x138
+#define H_PUT_TCE_INDIRECT      0x13C
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
+#define H_VTERM_PARTNER_INFO    0x150
+#define H_REGISTER_VTERM        0x154
+#define H_FREE_VTERM            0x158
+#define H_RESET_EVENTS          0x15C
+#define H_ALLOC_RESOURCE        0x160
+#define H_FREE_RESOURCE         0x164
+#define H_MODIFY_QP             0x168
+#define H_QUERY_QP              0x16C
+#define H_REREGISTER_PMR        0x170
+#define H_REGISTER_SMR          0x174
+#define H_QUERY_MR              0x178
+#define H_QUERY_MW              0x17C
+#define H_QUERY_HCA             0x180
+#define H_QUERY_PORT            0x184
+#define H_MODIFY_PORT           0x188
+#define H_DEFINE_AQP1           0x18C
+#define H_GET_TRACE_BUFFER      0x190
+#define H_DEFINE_AQP0           0x194
+#define H_RESIZE_MR             0x198
+#define H_ATTACH_MCQP           0x19C
+#define H_DETACH_MCQP           0x1A0
+#define H_CREATE_RPT            0x1A4
+#define H_REMOVE_RPT            0x1A8
+#define H_REGISTER_RPAGES       0x1AC
+#define H_DISABLE_AND_GETC      0x1B0
+#define H_ERROR_DATA            0x1B4
+#define H_GET_HCA_INFO          0x1B8
+#define H_GET_PERF_COUNT        0x1BC
+#define H_MANAGE_TRACE          0x1C0
+#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
+#define H_QUERY_INT_STATE       0x1E4
+#define H_POLL_PENDING          0x1D8
+#define H_ILLAN_ATTRIBUTES      0x244
+#define H_MODIFY_HEA_QP         0x250
+#define H_QUERY_HEA_QP          0x254
+#define H_QUERY_HEA             0x258
+#define H_QUERY_HEA_PORT        0x25C
+#define H_MODIFY_HEA_PORT       0x260
+#define H_REG_BCMC              0x264
+#define H_DEREG_BCMC            0x268
+#define H_REGISTER_HEA_RPAGES   0x26C
+#define H_DISABLE_AND_GET_HEA   0x270
+#define H_GET_HEA_INFO          0x274
+#define H_ALLOC_HEA_RESOURCE    0x278
+#define H_ADD_CONN              0x284
+#define H_DEL_CONN              0x288
+#define H_JOIN                  0x298
+#define H_VASI_STATE            0x2A4
+#define H_ENABLE_CRQ            0x2B0
+#define H_GET_EM_PARMS          0x2B8
+#define H_SET_MPP               0x2D0
+#define H_GET_MPP               0x2D4
+#define MAX_HCALL_OPCODE        H_GET_MPP
+
+/* The hcalls above are standardized in PAPR and implemented by pHyp
+ * as well.
+ *
+ * We also need some hcalls which are specific to qemu / KVM-on-POWER.
+ * So far we just need one for H_RTAS, but in future we'll need more
+ * for extensions like virtio.  We put those into the 0xf000-0xfffc
+ * range which is reserved by PAPR for "platform-specific" hcalls.
+ */
+#define KVMPPC_HCALL_BASE       0xf000
+#define KVMPPC_H_RTAS           (KVMPPC_HCALL_BASE + 0x0)
+#define KVMPPC_HCALL_MAX        KVMPPC_H_RTAS
+
+extern sPAPREnvironment *spapr;
+
+/*#define DEBUG_SPAPR_HCALLS*/
+
+#ifdef DEBUG_SPAPR_HCALLS
+#define hcall_dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define hcall_dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef target_ulong (*spapr_hcall_fn)(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode,
+                                       target_ulong *args);
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
+target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
+                             target_ulong *args);
+
+static inline uint32_t rtas_ld(target_ulong phys, int n)
+{
+    return ldl_phys(phys + 4*n);
+}
+
+static inline void rtas_st(target_ulong phys, int n, uint32_t val)
+{
+    stl_phys(phys + 4*n, val);
+}
+
+typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token,
+                              uint32_t nargs, target_ulong args,
+                              uint32_t nret, target_ulong rets);
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn);
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets);
+int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
+                                 target_phys_addr_t rtas_size);
+
+#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
new file mode 100644 (file)
index 0000000..f88e1d2
--- /dev/null
@@ -0,0 +1,525 @@
+#include "sysemu.h"
+#include "cpu.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "exec-all.h"
+#include "exec.h"
+#include "helper_regs.h"
+#include "hw/spapr.h"
+
+#define HPTES_PER_GROUP 8
+
+#define HPTE_V_SSIZE_SHIFT      62
+#define HPTE_V_AVPN_SHIFT       7
+#define HPTE_V_AVPN             0x3fffffffffffff80ULL
+#define HPTE_V_AVPN_VAL(x)      (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
+#define HPTE_V_COMPARE(x, y)    (!(((x) ^ (y)) & 0xffffffffffffff80UL))
+#define HPTE_V_BOLTED           0x0000000000000010ULL
+#define HPTE_V_LOCK             0x0000000000000008ULL
+#define HPTE_V_LARGE            0x0000000000000004ULL
+#define HPTE_V_SECONDARY        0x0000000000000002ULL
+#define HPTE_V_VALID            0x0000000000000001ULL
+
+#define HPTE_R_PP0              0x8000000000000000ULL
+#define HPTE_R_TS               0x4000000000000000ULL
+#define HPTE_R_KEY_HI           0x3000000000000000ULL
+#define HPTE_R_RPN_SHIFT        12
+#define HPTE_R_RPN              0x3ffffffffffff000ULL
+#define HPTE_R_FLAGS            0x00000000000003ffULL
+#define HPTE_R_PP               0x0000000000000003ULL
+#define HPTE_R_N                0x0000000000000004ULL
+#define HPTE_R_G                0x0000000000000008ULL
+#define HPTE_R_M                0x0000000000000010ULL
+#define HPTE_R_I                0x0000000000000020ULL
+#define HPTE_R_W                0x0000000000000040ULL
+#define HPTE_R_WIMG             0x0000000000000078ULL
+#define HPTE_R_C                0x0000000000000080ULL
+#define HPTE_R_R                0x0000000000000100ULL
+#define HPTE_R_KEY_LO           0x0000000000000e00ULL
+
+#define HPTE_V_1TB_SEG          0x4000000000000000ULL
+#define HPTE_V_VRMA_MASK        0x4001ffffff000000ULL
+
+#define HPTE_V_HVLOCK           0x40ULL
+
+static inline int lock_hpte(void *hpte, target_ulong bits)
+{
+    uint64_t pteh;
+
+    pteh = ldq_p(hpte);
+
+    /* We're protected by qemu's global lock here */
+    if (pteh & bits) {
+        return 0;
+    }
+    stq_p(hpte, pteh | HPTE_V_HVLOCK);
+    return 1;
+}
+
+static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
+                                     target_ulong pte_index)
+{
+    target_ulong rb, va_low;
+
+    rb = (v & ~0x7fULL) << 16; /* AVA field */
+    va_low = pte_index >> 3;
+    if (v & HPTE_V_SECONDARY) {
+        va_low = ~va_low;
+    }
+    /* xor vsid from AVA */
+    if (!(v & HPTE_V_1TB_SEG)) {
+        va_low ^= v >> 12;
+    } else {
+        va_low ^= v >> 24;
+    }
+    va_low &= 0x7ff;
+    if (v & HPTE_V_LARGE) {
+        rb |= 1;                         /* L field */
+#if 0 /* Disable that P7 specific bit for now */
+        if (r & 0xff000) {
+            /* non-16MB large page, must be 64k */
+            /* (masks depend on page size) */
+            rb |= 0x1000;                /* page encoding in LP field */
+            rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
+            rb |= (va_low & 0xfe);       /* AVAL field */
+        }
+#endif
+    } else {
+        /* 4kB page */
+        rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of AVA */
+    }
+    rb |= (v >> 54) & 0x300;            /* B field */
+    return rb;
+}
+
+static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr,
+                            target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong pteh = args[2];
+    target_ulong ptel = args[3];
+    target_ulong porder;
+    target_ulong i, pa;
+    uint8_t *hpte;
+
+    /* only handle 4k and 16M pages for now */
+    porder = 12;
+    if (pteh & HPTE_V_LARGE) {
+#if 0 /* We don't support 64k pages yet */
+        if ((ptel & 0xf000) == 0x1000) {
+            /* 64k page */
+            porder = 16;
+        } else
+#endif
+        if ((ptel & 0xff000) == 0) {
+            /* 16M page */
+            porder = 24;
+            /* lowest AVA bit must be 0 for 16M pages */
+            if (pteh & 0x80) {
+                return H_PARAMETER;
+            }
+        } else {
+            return H_PARAMETER;
+        }
+    }
+
+    pa = ptel & HPTE_R_RPN;
+    /* FIXME: bounds check the pa? */
+
+    /* Check WIMG */
+    if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
+        return H_PARAMETER;
+    }
+    pteh &= ~0x60ULL;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return H_PARAMETER;
+    }
+    if (likely((flags & H_EXACT) == 0)) {
+        pte_index &= ~7ULL;
+        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+        for (i = 0; ; ++i) {
+            if (i == 8) {
+                return H_PTEG_FULL;
+            }
+            if (((ldq_p(hpte) & HPTE_V_VALID) == 0) &&
+                lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) {
+                break;
+            }
+            hpte += HASH_PTE_SIZE_64;
+        }
+    } else {
+        i = 0;
+        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+        if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) {
+            return H_PTEG_FULL;
+        }
+    }
+    stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
+    /* eieio();  FIXME: need some sort of barrier for smp? */
+    stq_p(hpte, pteh);
+
+    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    args[0] = pte_index + i;
+    return H_SUCCESS;
+}
+
+static target_ulong h_remove(CPUState *env, sPAPREnvironment *spapr,
+                             target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong avpn = args[2];
+    uint8_t *hpte;
+    target_ulong v, r, rb;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return H_PARAMETER;
+    }
+
+    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+    while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
+        /* We have no real concurrency in qemu soft-emulation, so we
+         * will never actually have a contested lock */
+        assert(0);
+    }
+
+    v = ldq_p(hpte);
+    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+
+    if ((v & HPTE_V_VALID) == 0 ||
+        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
+        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
+        stq_p(hpte, v & ~HPTE_V_HVLOCK);
+        assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+        return H_NOT_FOUND;
+    }
+    args[0] = v & ~HPTE_V_HVLOCK;
+    args[1] = r;
+    stq_p(hpte, 0);
+    rb = compute_tlbie_rb(v, r, pte_index);
+    ppc_tlb_invalidate_one(env, rb);
+    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    return H_SUCCESS;
+}
+
+static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong avpn = args[2];
+    uint8_t *hpte;
+    target_ulong v, r, rb;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return H_PARAMETER;
+    }
+
+    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+    while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
+        /* We have no real concurrency in qemu soft-emulation, so we
+         * will never actually have a contested lock */
+        assert(0);
+    }
+
+    v = ldq_p(hpte);
+    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+
+    if ((v & HPTE_V_VALID) == 0 ||
+        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
+        stq_p(hpte, v & ~HPTE_V_HVLOCK);
+        assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+        return H_NOT_FOUND;
+    }
+
+    r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
+           HPTE_R_KEY_HI | HPTE_R_KEY_LO);
+    r |= (flags << 55) & HPTE_R_PP0;
+    r |= (flags << 48) & HPTE_R_KEY_HI;
+    r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
+    rb = compute_tlbie_rb(v, r, pte_index);
+    stq_p(hpte, v & ~HPTE_V_VALID);
+    ppc_tlb_invalidate_one(env, rb);
+    stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
+    /* Don't need a memory barrier, due to qemu's global lock */
+    stq_p(hpte, v & ~HPTE_V_HVLOCK);
+    assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    return H_SUCCESS;
+}
+
+static target_ulong h_set_dabr(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    /* FIXME: actually implement this */
+    return H_HARDWARE;
+}
+
+#define FLAGS_REGISTER_VPA         0x0000200000000000ULL
+#define FLAGS_REGISTER_DTL         0x0000400000000000ULL
+#define FLAGS_REGISTER_SLBSHADOW   0x0000600000000000ULL
+#define FLAGS_DEREGISTER_VPA       0x0000a00000000000ULL
+#define FLAGS_DEREGISTER_DTL       0x0000c00000000000ULL
+#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
+
+#define VPA_MIN_SIZE           640
+#define VPA_SIZE_OFFSET        0x4
+#define VPA_SHARED_PROC_OFFSET 0x9
+#define VPA_SHARED_PROC_VAL    0x2
+
+static target_ulong register_vpa(CPUState *env, target_ulong vpa)
+{
+    uint16_t size;
+    uint8_t tmp;
+
+    if (vpa == 0) {
+        hcall_dprintf("Can't cope with registering a VPA at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    if (vpa % env->dcache_line_size) {
+        return H_PARAMETER;
+    }
+    /* FIXME: bounds check the address */
+
+    size = lduw_phys(vpa + 0x4);
+
+    if (size < VPA_MIN_SIZE) {
+        return H_PARAMETER;
+    }
+
+    /* VPA is not allowed to cross a page boundary */
+    if ((vpa / 4096) != ((vpa + size - 1) / 4096)) {
+        return H_PARAMETER;
+    }
+
+    env->vpa = vpa;
+
+    tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET);
+    tmp |= VPA_SHARED_PROC_VAL;
+    stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp);
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_vpa(CPUState *env, target_ulong vpa)
+{
+    if (env->slb_shadow) {
+        return H_RESOURCE;
+    }
+
+    if (env->dispatch_trace_log) {
+        return H_RESOURCE;
+    }
+
+    env->vpa = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong register_slb_shadow(CPUState *env, target_ulong addr)
+{
+    uint32_t size;
+
+    if (addr == 0) {
+        hcall_dprintf("Can't cope with SLB shadow at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    size = ldl_phys(addr + 0x4);
+    if (size < 0x8) {
+        return H_PARAMETER;
+    }
+
+    if ((addr / 4096) != ((addr + size - 1) / 4096)) {
+        return H_PARAMETER;
+    }
+
+    if (!env->vpa) {
+        return H_RESOURCE;
+    }
+
+    env->slb_shadow = addr;
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_slb_shadow(CPUState *env, target_ulong addr)
+{
+    env->slb_shadow = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong register_dtl(CPUState *env, target_ulong addr)
+{
+    uint32_t size;
+
+    if (addr == 0) {
+        hcall_dprintf("Can't cope with DTL at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    size = ldl_phys(addr + 0x4);
+
+    if (size < 48) {
+        return H_PARAMETER;
+    }
+
+    if (!env->vpa) {
+        return H_RESOURCE;
+    }
+
+    env->dispatch_trace_log = addr;
+    env->dtl_size = size;
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_dtl(CPUState *emv, target_ulong addr)
+{
+    env->dispatch_trace_log = 0;
+    env->dtl_size = 0;
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_register_vpa(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong procno = args[1];
+    target_ulong vpa = args[2];
+    target_ulong ret = H_PARAMETER;
+    CPUState *tenv;
+
+    for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) {
+        if (tenv->cpu_index == procno) {
+            break;
+        }
+    }
+
+    if (!tenv) {
+        return H_PARAMETER;
+    }
+
+    switch (flags) {
+    case FLAGS_REGISTER_VPA:
+        ret = register_vpa(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_VPA:
+        ret = deregister_vpa(tenv, vpa);
+        break;
+
+    case FLAGS_REGISTER_SLBSHADOW:
+        ret = register_slb_shadow(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_SLBSHADOW:
+        ret = deregister_slb_shadow(tenv, vpa);
+        break;
+
+    case FLAGS_REGISTER_DTL:
+        ret = register_dtl(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_DTL:
+        ret = deregister_dtl(tenv, vpa);
+        break;
+    }
+
+    return ret;
+}
+
+static target_ulong h_cede(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    env->msr |= (1ULL << MSR_EE);
+    hreg_compute_hflags(env);
+    if (!cpu_has_work(env)) {
+        env->halted = 1;
+    }
+    return H_SUCCESS;
+}
+
+static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    target_ulong rtas_r3 = args[0];
+    uint32_t token = ldl_phys(rtas_r3);
+    uint32_t nargs = ldl_phys(rtas_r3 + 4);
+    uint32_t nret = ldl_phys(rtas_r3 + 8);
+
+    return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
+                           nret, rtas_r3 + 12 + 4*nargs);
+}
+
+spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
+spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE];
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
+{
+    spapr_hcall_fn *slot;
+
+    if (opcode <= MAX_HCALL_OPCODE) {
+        assert((opcode & 0x3) == 0);
+
+        slot = &papr_hypercall_table[opcode / 4];
+    } else {
+        assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
+
+
+        slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
+    }
+
+    assert(!(*slot) || (fn == *slot));
+    *slot = fn;
+}
+
+target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
+                             target_ulong *args)
+{
+    if (msr_pr) {
+        hcall_dprintf("Hypercall made with MSR[PR]=1\n");
+        return H_PRIVILEGE;
+    }
+
+    if ((opcode <= MAX_HCALL_OPCODE)
+        && ((opcode & 0x3) == 0)) {
+        spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
+
+        if (fn) {
+            return fn(env, spapr, opcode, args);
+        }
+    } else if ((opcode >= KVMPPC_HCALL_BASE) &&
+               (opcode <= KVMPPC_HCALL_MAX)) {
+        spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
+
+        if (fn) {
+            return fn(env, spapr, opcode, args);
+        }
+    }
+
+    hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
+    return H_FUNCTION;
+}
+
+static void hypercall_init(void)
+{
+    /* hcall-pft */
+    spapr_register_hypercall(H_ENTER, h_enter);
+    spapr_register_hypercall(H_REMOVE, h_remove);
+    spapr_register_hypercall(H_PROTECT, h_protect);
+
+    /* hcall-dabr */
+    spapr_register_hypercall(H_SET_DABR, h_set_dabr);
+
+    /* hcall-splpar */
+    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
+    spapr_register_hypercall(H_CEDE, h_cede);
+
+    /* qemu/KVM-PPC specific hcalls */
+    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
+}
+device_init(hypercall_init);
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
new file mode 100644 (file)
index 0000000..ff3a78f
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Inter-VM Logical Lan, aka ibmveth
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#include "hw.h"
+#include "net.h"
+#include "hw/qdev.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define ETH_ALEN        6
+#define MAX_PACKET_SIZE 65536
+
+/*#define DEBUG*/
+
+#ifdef DEBUG
+#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0)
+#else
+#define dprintf(fmt...)
+#endif
+
+/*
+ * Virtual LAN device
+ */
+
+typedef uint64_t vlan_bd_t;
+
+#define VLAN_BD_VALID        0x8000000000000000ULL
+#define VLAN_BD_TOGGLE       0x4000000000000000ULL
+#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
+#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
+#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
+#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
+#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
+#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)
+
+#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
+                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
+                                  (addr & VLAN_BD_ADDR_MASK))
+
+#define VLAN_RXQC_TOGGLE     0x80
+#define VLAN_RXQC_VALID      0x40
+#define VLAN_RXQC_NO_CSUM    0x02
+#define VLAN_RXQC_CSUM_GOOD  0x01
+
+#define VLAN_RQ_ALIGNMENT    16
+#define VLAN_RXQ_BD_OFF      0
+#define VLAN_FILTER_BD_OFF   8
+#define VLAN_RX_BDS_OFF      16
+#define VLAN_MAX_BUFS        ((SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
+
+typedef struct VIOsPAPRVLANDevice {
+    VIOsPAPRDevice sdev;
+    NICConf nicconf;
+    NICState *nic;
+    int isopen;
+    target_ulong buf_list;
+    int add_buf_ptr, use_buf_ptr, rx_bufs;
+    target_ulong rxq_ptr;
+} VIOsPAPRVLANDevice;
+
+static int spapr_vlan_can_receive(VLANClientState *nc)
+{
+    VIOsPAPRVLANDevice *dev = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    return (dev->isopen && dev->rx_bufs > 0);
+}
+
+static ssize_t spapr_vlan_receive(VLANClientState *nc, const uint8_t *buf,
+                                  size_t size)
+{
+    VIOsPAPRDevice *sdev = DO_UPCAST(NICState, nc, nc)->opaque;
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t rxq_bd = ldq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
+    vlan_bd_t bd;
+    int buf_ptr = dev->use_buf_ptr;
+    uint64_t handle;
+    uint8_t control;
+
+    dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
+            dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return -1;
+    }
+
+    if (!dev->rx_bufs) {
+        return -1;
+    }
+
+    do {
+        buf_ptr += 8;
+        if (buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) {
+            buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = ldq_tce(sdev, dev->buf_list + buf_ptr);
+        dprintf("use_buf_ptr=%d bd=0x%016llx\n",
+                buf_ptr, (unsigned long long)bd);
+    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
+             && (buf_ptr != dev->use_buf_ptr));
+
+    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
+        /* Failed to find a suitable buffer */
+        return -1;
+    }
+
+    /* Remove the buffer from the pool */
+    dev->rx_bufs--;
+    dev->use_buf_ptr = buf_ptr;
+    stq_tce(sdev, dev->buf_list + dev->use_buf_ptr, 0);
+
+    dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
+
+    /* Transfer the packet data */
+    if (spapr_tce_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
+        return -1;
+    }
+
+    dprintf("spapr_vlan_receive: DMA write completed\n");
+
+    /* Update the receive queue */
+    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
+    if (rxq_bd & VLAN_BD_TOGGLE) {
+        control ^= VLAN_RXQC_TOGGLE;
+    }
+
+    handle = ldq_tce(sdev, VLAN_BD_ADDR(bd));
+    stq_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
+    stw_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
+    sth_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
+    stb_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
+
+    dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
+            (unsigned long long)dev->rxq_ptr,
+            (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr),
+            (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr + 8));
+
+    dev->rxq_ptr += 16;
+    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
+        dev->rxq_ptr = 0;
+        stq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
+    }
+
+    if (sdev->signal_state & 1) {
+        qemu_irq_pulse(sdev->qirq);
+    }
+
+    return size;
+}
+
+static NetClientInfo net_spapr_vlan_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = spapr_vlan_can_receive,
+    .receive = spapr_vlan_receive,
+};
+
+static int spapr_vlan_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    VIOsPAPRBus *bus;
+
+    bus = DO_UPCAST(VIOsPAPRBus, bus, sdev->qdev.parent_bus);
+
+    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
+
+    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
+                            sdev->qdev.info->name, sdev->qdev.id, dev);
+    qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a);
+
+    return 0;
+}
+
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
+                       qemu_irq qirq, uint32_t vio_irq_num)
+{
+    DeviceState *dev;
+    VIOsPAPRDevice *sdev;
+
+    dev = qdev_create(&bus->bus, "spapr-vlan");
+    qdev_prop_set_uint32(dev, "reg", reg);
+
+    qdev_set_nic_properties(dev, nd);
+
+    qdev_init_nofail(dev);
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
+}
+
+static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev;
+    uint8_t padded_mac[8] = {0, 0};
+    int ret;
+
+    /* Some old phyp versions give the mac address in an 8-byte
+     * property.  The kernel driver has an insane workaround for this;
+     * rather than doing the obvious thing and checking the property
+     * length, it checks whether the first byte has 0b10 in the low
+     * bits.  If a correct 6-byte property has a different first byte
+     * the kernel will get the wrong mac address, overrunning its
+     * buffer in the process (read only, thank goodness).
+     *
+     * Here we workaround the kernel workaround by always supplying an
+     * 8-byte property, with the mac address in the last six bytes */
+    memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
+    ret = fdt_setprop(fdt, node_off, "local-mac-address",
+                      padded_mac, sizeof(padded_mac));
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
+                    target_ulong alignment)
+{
+    if ((VLAN_BD_ADDR(bd) % alignment)
+        || (VLAN_BD_LEN(bd) % alignment)) {
+        return -1;
+    }
+
+    if (spapr_vio_check_tces(&dev->sdev, VLAN_BD_ADDR(bd),
+                             VLAN_BD_LEN(bd), SPAPR_TCE_RW) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static target_ulong h_register_logical_lan(CPUState *env,
+                                           sPAPREnvironment *spapr,
+                                           target_ulong opcode,
+                                           target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf_list = args[1];
+    target_ulong rec_queue = args[2];
+    target_ulong filter_list = args[3];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t filter_list_bd;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (dev->isopen) {
+        hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
+                      "H_FREE_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    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);
+        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);
+        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");
+        return H_PARAMETER;
+    }
+
+    dev->buf_list = buf_list;
+    sdev->signal_state = 0;
+
+    rec_queue &= ~VLAN_BD_TOGGLE;
+
+    /* Initialize the buffer list */
+    stq_tce(sdev, buf_list, rec_queue);
+    stq_tce(sdev, buf_list + 8, filter_list_bd);
+    spapr_tce_dma_zero(sdev, buf_list + VLAN_RX_BDS_OFF,
+                       SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
+    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->rx_bufs = 0;
+    dev->rxq_ptr = 0;
+
+    /* Initialize the receive queue */
+    spapr_tce_dma_zero(sdev, VLAN_BD_ADDR(rec_queue), VLAN_BD_LEN(rec_queue));
+
+    dev->isopen = 1;
+    return H_SUCCESS;
+}
+
+
+static target_ulong h_free_logical_lan(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen) {
+        hcall_dprintf("H_FREE_LOGICAL_LAN called without "
+                      "H_REGISTER_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    dev->buf_list = 0;
+    dev->rx_bufs = 0;
+    dev->isopen = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong h_add_logical_lan_buffer(CPUState *env,
+                                             sPAPREnvironment *spapr,
+                                             target_ulong opcode,
+                                             target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf = args[1];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t bd;
+
+    dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
+            ", 0x" TARGET_FMT_lx ")\n", reg, buf);
+
+    if (!sdev) {
+        hcall_dprintf("Wrong device in h_add_logical_lan_buffer\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");
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
+        return H_RESOURCE;
+    }
+
+    do {
+        dev->add_buf_ptr += 8;
+        if (dev->add_buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) {
+            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = ldq_tce(sdev, dev->buf_list + dev->add_buf_ptr);
+    } while (bd & VLAN_BD_VALID);
+
+    stq_tce(sdev, dev->buf_list + dev->add_buf_ptr, buf);
+
+    dev->rx_bufs++;
+
+    dprintf("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
+            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
+            (unsigned long long)buf);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_send_logical_lan(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *bufs = args + 1;
+    target_ulong continue_token = args[7];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    unsigned total_len;
+    uint8_t *lbuf, *p;
+    int i, nbufs;
+    int ret;
+
+    dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
+            TARGET_FMT_lx ")\n", reg, continue_token);
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    dprintf("rxbufs = %d\n", dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return H_DROPPED;
+    }
+
+    if (continue_token) {
+        return H_HARDWARE; /* FIXME actually handle this */
+    }
+
+    total_len = 0;
+    for (i = 0; i < 6; i++) {
+        dprintf("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
+        if (!(bufs[i] & VLAN_BD_VALID)) {
+            break;
+        }
+        total_len += VLAN_BD_LEN(bufs[i]);
+    }
+
+    nbufs = i;
+    dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n",
+            nbufs, total_len);
+
+    if (total_len == 0) {
+        return H_SUCCESS;
+    }
+
+    if (total_len > MAX_PACKET_SIZE) {
+        /* Don't let the guest force too large an allocation */
+        return H_RESOURCE;
+    }
+
+    lbuf = alloca(total_len);
+    p = lbuf;
+    for (i = 0; i < nbufs; i++) {
+        ret = spapr_tce_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
+                                 p, VLAN_BD_LEN(bufs[i]));
+        if (ret < 0) {
+            return ret;
+        }
+
+        p += VLAN_BD_LEN(bufs[i]);
+    }
+
+    qemu_send_packet(&dev->nic->nc, lbuf, total_len);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
+                                     target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    return H_SUCCESS;
+}
+
+static void vlan_hcalls(VIOsPAPRBus *bus)
+{
+    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
+    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
+    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
+    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
+                             h_add_logical_lan_buffer);
+    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
+}
+
+static VIOsPAPRDeviceInfo spapr_vlan = {
+    .init = spapr_vlan_init,
+    .devnode = spapr_vlan_devnode,
+    .dt_name = "l-lan",
+    .dt_type = "network",
+    .dt_compatible = "IBM,l-lan",
+    .signal_mask = 0x1,
+    .hcalls = vlan_hcalls,
+    .qdev.name = "spapr-vlan",
+    .qdev.size = sizeof(VIOsPAPRVLANDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x1000),
+        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, rtce_window_size,
+                           0x10000000),
+        DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vlan_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vlan);
+}
+device_init(spapr_vlan_register);
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
new file mode 100644 (file)
index 0000000..16b6542
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Hypercall based emulated RTAS
+ *
+ * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#include "cpu.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "hw/qdev.h"
+#include "device_tree.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define TOKEN_BASE      0x2000
+#define TOKEN_MAX       0x100
+
+static void rtas_display_character(sPAPREnvironment *spapr,
+                                   uint32_t token, uint32_t nargs,
+                                   target_ulong args,
+                                   uint32_t nret, target_ulong rets)
+{
+    uint8_t c = rtas_ld(args, 0);
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, 0);
+
+    if (!sdev) {
+        rtas_st(rets, 0, -1);
+    } else {
+        vty_putchars(sdev, &c, sizeof(c));
+        rtas_st(rets, 0, 0);
+    }
+}
+
+static void rtas_get_time_of_day(sPAPREnvironment *spapr,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+    struct tm tm;
+
+    if (nret != 8) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    qemu_get_timedate(&tm, 0);
+
+    rtas_st(rets, 0, 0); /* Success */
+    rtas_st(rets, 1, tm.tm_year + 1900);
+    rtas_st(rets, 2, tm.tm_mon + 1);
+    rtas_st(rets, 3, tm.tm_mday);
+    rtas_st(rets, 4, tm.tm_hour);
+    rtas_st(rets, 5, tm.tm_min);
+    rtas_st(rets, 6, tm.tm_sec);
+    rtas_st(rets, 7, 0); /* we don't do nanoseconds */
+}
+
+static void rtas_power_off(sPAPREnvironment *spapr,
+                           uint32_t token, uint32_t nargs, target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+    if (nargs != 2 || nret != 1) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    qemu_system_shutdown_request();
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr,
+                                         uint32_t token, uint32_t nargs,
+                                         target_ulong args,
+                                         uint32_t nret, target_ulong rets)
+{
+    target_ulong id;
+    CPUState *env;
+
+    if (nargs != 1 || nret != 2) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    id = rtas_ld(args, 0);
+    for (env = first_cpu; env; env = env->next_cpu) {
+        if (env->cpu_index != id) {
+            continue;
+        }
+
+        if (env->halted) {
+            rtas_st(rets, 1, 0);
+        } else {
+            rtas_st(rets, 1, 2);
+        }
+
+        rtas_st(rets, 0, 0);
+        return;
+    }
+
+    /* Didn't find a matching cpu */
+    rtas_st(rets, 0, -3);
+}
+
+static void rtas_start_cpu(sPAPREnvironment *spapr,
+                           uint32_t token, uint32_t nargs,
+                           target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+    target_ulong id, start, r3;
+    CPUState *env;
+
+    if (nargs != 3 || nret != 1) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    id = rtas_ld(args, 0);
+    start = rtas_ld(args, 1);
+    r3 = rtas_ld(args, 2);
+
+    for (env = first_cpu; env; env = env->next_cpu) {
+        if (env->cpu_index != id) {
+            continue;
+        }
+
+        if (!env->halted) {
+            rtas_st(rets, 0, -1);
+            return;
+        }
+
+        env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
+        env->nip = start;
+        env->gpr[3] = r3;
+        env->halted = 0;
+
+        qemu_cpu_kick(env);
+
+        rtas_st(rets, 0, 0);
+        return;
+    }
+
+    /* Didn't find a matching cpu */
+    rtas_st(rets, 0, -3);
+}
+
+static struct rtas_call {
+    const char *name;
+    spapr_rtas_fn fn;
+} rtas_table[TOKEN_MAX];
+
+struct rtas_call *rtas_next = rtas_table;
+
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets)
+{
+    if ((token >= TOKEN_BASE)
+        && ((token - TOKEN_BASE) < TOKEN_MAX)) {
+        struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
+
+        if (call->fn) {
+            call->fn(spapr, token, nargs, args, nret, rets);
+            return H_SUCCESS;
+        }
+    }
+
+    /* HACK: Some Linux early debug code uses RTAS display-character,
+     * but assumes the token value is 0xa (which it is on some real
+     * machines) without looking it up in the device tree.  This
+     * special case makes this work */
+    if (token == 0xa) {
+        rtas_display_character(spapr, 0xa, nargs, args, nret, rets);
+        return H_SUCCESS;
+    }
+
+    hcall_dprintf("Unknown RTAS token 0x%x\n", token);
+    rtas_st(rets, 0, -3);
+    return H_PARAMETER;
+}
+
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
+{
+    assert(rtas_next < (rtas_table + TOKEN_MAX));
+
+    rtas_next->name = name;
+    rtas_next->fn = fn;
+
+    rtas_next++;
+}
+
+int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
+                                 target_phys_addr_t rtas_size)
+{
+    int ret;
+    int i;
+
+    ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base",
+                                    rtas_addr);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
+                                    rtas_addr);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size",
+                                    rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add rtas-size property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    for (i = 0; i < TOKEN_MAX; i++) {
+        struct rtas_call *call = &rtas_table[i];
+
+        if (!call->fn) {
+            continue;
+        }
+
+        ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name,
+                                        i + TOKEN_BASE);
+        if (ret < 0) {
+            fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
+                    call->name, fdt_strerror(ret));
+            return ret;
+        }
+
+    }
+    return 0;
+}
+
+static void register_core_rtas(void)
+{
+    spapr_rtas_register("display-character", rtas_display_character);
+    spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
+    spapr_rtas_register("power-off", rtas_power_off);
+    spapr_rtas_register("query-cpu-stopped-state",
+                        rtas_query_cpu_stopped_state);
+    spapr_rtas_register("start-cpu", rtas_start_cpu);
+}
+device_init(register_core_rtas);
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
new file mode 100644 (file)
index 0000000..481a804
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ * QEMU sPAPR VIO code
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
+ * Based on the s390 virtio bus code:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * 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 "hw.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "monitor.h"
+#include "loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "kvm.h"
+#include "device_tree.h"
+#include "kvm_ppc.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#ifdef CONFIG_FDT
+#include <libfdt.h>
+#endif /* CONFIG_FDT */
+
+/* #define DEBUG_SPAPR */
+/* #define DEBUG_TCE */
+
+#ifdef DEBUG_SPAPR
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static struct BusInfo spapr_vio_bus_info = {
+    .name       = "spapr-vio",
+    .size       = sizeof(VIOsPAPRBus),
+};
+
+VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
+{
+    DeviceState *qdev;
+    VIOsPAPRDevice *dev = NULL;
+
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)qdev;
+        if (dev->reg == reg) {
+            break;
+        }
+    }
+
+    return dev;
+}
+
+#ifdef CONFIG_FDT
+static int vio_make_devnode(VIOsPAPRDevice *dev,
+                            void *fdt)
+{
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    int vdevice_off, node_off;
+    int ret;
+
+    vdevice_off = fdt_path_offset(fdt, "/vdevice");
+    if (vdevice_off < 0) {
+        return vdevice_off;
+    }
+
+    node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id);
+    if (node_off < 0) {
+        return node_off;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (info->dt_type) {
+        ret = fdt_setprop_string(fdt, node_off, "device_type",
+                                 info->dt_type);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (info->dt_compatible) {
+        ret = fdt_setprop_string(fdt, node_off, "compatible",
+                                 info->dt_compatible);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (dev->qirq) {
+        uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
+
+        ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
+                          sizeof(ints_prop));
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (dev->rtce_window_size) {
+        uint32_t dma_prop[] = {cpu_to_be32(dev->reg),
+                               0, 0,
+                               0, cpu_to_be32(dev->rtce_window_size)};
+
+        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ret = fdt_setprop(fdt, node_off, "ibm,my-dma-window", dma_prop,
+                          sizeof(dma_prop));
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (info->devnode) {
+        ret = (info->devnode)(dev, fdt, node_off);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    return node_off;
+}
+#endif /* CONFIG_FDT */
+
+/*
+ * RTCE handling
+ */
+
+static void rtce_init(VIOsPAPRDevice *dev)
+{
+    size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
+        * sizeof(VIOsPAPR_RTCE);
+
+    if (size) {
+        dev->rtce_table = qemu_mallocz(size);
+    }
+}
+
+static target_ulong h_put_tce(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong liobn = args[0];
+    target_ulong ioba = args[1];
+    target_ulong tce = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, liobn);
+    VIOsPAPR_RTCE *rtce;
+
+    if (!dev) {
+        hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN "
+                      TARGET_FMT_lx "\n", liobn);
+        return H_PARAMETER;
+    }
+
+    ioba &= ~(SPAPR_VIO_TCE_PAGE_SIZE - 1);
+
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_vio_put_tce on %s  ioba 0x" TARGET_FMT_lx
+            "  TCE 0x" TARGET_FMT_lx "\n", dev->qdev.id, ioba, tce);
+#endif
+
+    if (ioba >= dev->rtce_window_size) {
+        hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
+                      TARGET_FMT_lx "\n", ioba);
+        return H_PARAMETER;
+    }
+
+    rtce = dev->rtce_table + (ioba >> SPAPR_VIO_TCE_PAGE_SHIFT);
+    rtce->tce = tce;
+
+    return H_SUCCESS;
+}
+
+int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
+                         target_ulong len, enum VIOsPAPR_TCEAccess access)
+{
+    int start, end, i;
+
+    start = ioba >> SPAPR_VIO_TCE_PAGE_SHIFT;
+    end = (ioba + len - 1) >> SPAPR_VIO_TCE_PAGE_SHIFT;
+
+    for (i = start; i <= end; i++) {
+        if ((dev->rtce_table[i].tce & access) != access) {
+#ifdef DEBUG_TCE
+            fprintf(stderr, "FAIL on %d\n", i);
+#endif
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf,
+                        uint32_t size)
+{
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    /* Check for bypass */
+    if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
+        cpu_physical_memory_write(taddr, buf, size);
+        return 0;
+    }
+
+    while (size) {
+        uint64_t tce;
+        uint32_t lsize;
+        uint64_t txaddr;
+
+        /* Check if we are in bound */
+        if (taddr >= dev->rtce_window_size) {
+#ifdef DEBUG_TCE
+            fprintf(stderr, "spapr_tce_dma_write out of bounds\n");
+#endif
+            return H_DEST_PARM;
+        }
+        tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
+
+        /* How much til end of page ? */
+        lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
+
+        /* Check TCE */
+        if (!(tce & 2)) {
+            return H_DEST_PARM;
+        }
+
+        /* Translate */
+        txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) |
+            (taddr & SPAPR_VIO_TCE_PAGE_MASK);
+
+#ifdef DEBUG_TCE
+        fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
+                (unsigned long long)txaddr, lsize);
+#endif
+
+        /* Do it */
+        cpu_physical_memory_write(txaddr, buf, lsize);
+        buf += lsize;
+        taddr += lsize;
+        size -= lsize;
+    }
+    return 0;
+}
+
+int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size)
+{
+    /* FIXME: allocating a temp buffer is nasty, but just stepping
+     * through writing zeroes is awkward.  This will do for now. */
+    uint8_t zeroes[size];
+
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_zero taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    memset(zeroes, 0, size);
+    return spapr_tce_dma_write(dev, taddr, zeroes, size);
+}
+
+void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val)
+{
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val)
+{
+    val = tswap16(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+
+void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val)
+{
+    val = tswap32(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val)
+{
+    val = tswap64(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf,
+                       uint32_t size)
+{
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    /* Check for bypass */
+    if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
+        cpu_physical_memory_read(taddr, buf, size);
+        return 0;
+    }
+
+    while (size) {
+        uint64_t tce;
+        uint32_t lsize;
+        uint64_t txaddr;
+
+        /* Check if we are in bound */
+        if (taddr >= dev->rtce_window_size) {
+#ifdef DEBUG_TCE
+            fprintf(stderr, "spapr_tce_dma_read out of bounds\n");
+#endif
+            return H_DEST_PARM;
+        }
+        tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
+
+        /* How much til end of page ? */
+        lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
+
+        /* Check TCE */
+        if (!(tce & 1)) {
+            return H_DEST_PARM;
+        }
+
+        /* Translate */
+        txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) |
+            (taddr & SPAPR_VIO_TCE_PAGE_MASK);
+
+#ifdef DEBUG_TCE
+        fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
+                (unsigned long long)txaddr, lsize);
+#endif
+        /* Do it */
+        cpu_physical_memory_read(txaddr, buf, lsize);
+        buf += lsize;
+        taddr += lsize;
+        size -= lsize;
+    }
+    return H_SUCCESS;
+}
+
+uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr)
+{
+    uint64_t val;
+
+    spapr_tce_dma_read(dev, taddr, &val, sizeof(val));
+    return tswap64(val);
+}
+
+/*
+ * CRQ handling
+ */
+static target_ulong h_reg_crq(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong queue_addr = args[1];
+    target_ulong queue_len = args[2];
+    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);
+        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);
+        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);
+        return H_PARAMETER;
+    }
+
+    /* Check if device supports CRQs */
+    if (!dev->crq.SendFunc) {
+        return H_NOT_FOUND;
+    }
+
+
+    /* Already a queue ? */
+    if (dev->crq.qsize) {
+        return H_RESOURCE;
+    }
+    dev->crq.qladdr = queue_addr;
+    dev->crq.qsize = queue_len;
+    dev->crq.qnext = 0;
+
+    dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x"
+            TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n",
+            reg, queue_addr, queue_len);
+    return H_SUCCESS;
+}
+
+static target_ulong h_free_crq(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    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);
+        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;
+}
+
+static target_ulong h_send_crq(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong msg_hi = args[1];
+    target_ulong msg_lo = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint64_t crq_mangle[2];
+
+    if (!dev) {
+        hcall_dprintf("h_send_crq on non-existent unit 0x"
+                      TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+    crq_mangle[0] = cpu_to_be64(msg_hi);
+    crq_mangle[1] = cpu_to_be64(msg_lo);
+
+    if (dev->crq.SendFunc) {
+        return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle);
+    }
+
+    return H_HARDWARE;
+}
+
+static target_ulong h_enable_crq(CPUState *env, sPAPREnvironment *spapr,
+                                 target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    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);
+        return H_PARAMETER;
+    }
+
+    return 0;
+}
+
+/* Returns negative error, 0 success, or positive: queue full */
+int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
+{
+    int rc;
+    uint8_t byte;
+
+    if (!dev->crq.qsize) {
+        fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
+        return -1;
+    }
+
+    /* Maybe do a fast path for KVM just writing to the pages */
+    rc = spapr_tce_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1);
+    if (rc) {
+        return rc;
+    }
+    if (byte != 0) {
+        return 1;
+    }
+
+    rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8,
+                             &crq[8], 8);
+    if (rc) {
+        return rc;
+    }
+
+    kvmppc_eieio();
+
+    rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8);
+    if (rc) {
+        return rc;
+    }
+
+    dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
+
+    if (dev->signal_state & 1) {
+        qemu_irq_pulse(dev->qirq);
+    }
+
+    return 0;
+}
+
+/* "quiesce" handling */
+
+static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
+{
+    dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
+
+    if (dev->rtce_table) {
+        size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
+            * sizeof(VIOsPAPR_RTCE);
+        memset(dev->rtce_table, 0, size);
+    }
+
+    dev->crq.qladdr = 0;
+    dev->crq.qsize = 0;
+    dev->crq.qnext = 0;
+}
+
+static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token,
+                                uint32_t nargs, target_ulong args,
+                                uint32_t nret, target_ulong rets)
+{
+    VIOsPAPRBus *bus = spapr->vio_bus;
+    VIOsPAPRDevice *dev;
+    uint32_t unit, enable;
+
+    if (nargs != 2) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    unit = rtas_ld(args, 0);
+    enable = rtas_ld(args, 1);
+    dev = spapr_vio_find_by_reg(bus, unit);
+    if (!dev) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    if (enable) {
+        dev->flags |= VIO_PAPR_FLAG_DMA_BYPASS;
+    } else {
+        dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
+    }
+
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+    VIOsPAPRBus *bus = spapr->vio_bus;
+    DeviceState *qdev;
+    VIOsPAPRDevice *dev = NULL;
+
+    if (nargs != 0) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)qdev;
+        spapr_vio_quiesce_one(dev);
+    }
+
+    rtas_st(rets, 0, 0);
+}
+
+static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
+{
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
+    VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+    char *id;
+
+    if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
+        return -1;
+    }
+
+    dev->qdev.id = id;
+
+    rtce_init(dev);
+
+    return info->init(dev);
+}
+
+void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
+{
+    info->qdev.init = spapr_vio_busdev_init;
+    info->qdev.bus_info = &spapr_vio_bus_info;
+
+    assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
+    qdev_register(&info->qdev);
+}
+
+static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
+                                 target_ulong opcode,
+                                 target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong mode = args[1];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRDeviceInfo *info;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+
+    if (mode & ~info->signal_mask) {
+        return H_PARAMETER;
+    }
+
+    dev->signal_state = mode;
+
+    return H_SUCCESS;
+}
+
+VIOsPAPRBus *spapr_vio_bus_init(void)
+{
+    VIOsPAPRBus *bus;
+    BusState *qbus;
+    DeviceState *dev;
+    DeviceInfo *qinfo;
+
+    /* Create bridge device */
+    dev = qdev_create(NULL, "spapr-vio-bridge");
+    qdev_init_nofail(dev);
+
+    /* Create bus on bridge device */
+
+    qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
+    bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
+
+    /* hcall-vio */
+    spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
+
+    /* hcall-tce */
+    spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+
+    /* hcall-crq */
+    spapr_register_hypercall(H_REG_CRQ, h_reg_crq);
+    spapr_register_hypercall(H_FREE_CRQ, h_free_crq);
+    spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
+    spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
+
+    /* RTAS calls */
+    spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
+    spapr_rtas_register("quiesce", rtas_quiesce);
+
+    for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
+        VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
+
+        if (qinfo->bus_info != &spapr_vio_bus_info) {
+            continue;
+        }
+
+        if (info->hcalls) {
+            info->hcalls(bus);
+        }
+    }
+
+    return bus;
+}
+
+/* Represents sPAPR hcall VIO devices */
+
+static int spapr_vio_bridge_init(SysBusDevice *dev)
+{
+    /* nothing */
+    return 0;
+}
+
+static SysBusDeviceInfo spapr_vio_bridge_info = {
+    .init = spapr_vio_bridge_init,
+    .qdev.name  = "spapr-vio-bridge",
+    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.no_user = 1,
+};
+
+static void spapr_vio_register_devices(void)
+{
+    sysbus_register_withprop(&spapr_vio_bridge_info);
+}
+
+device_init(spapr_vio_register_devices)
+
+#ifdef CONFIG_FDT
+int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
+{
+    DeviceState *qdev;
+    int ret = 0;
+
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+
+        ret = vio_make_devnode(dev, fdt);
+
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    return 0;
+}
+#endif /* CONFIG_FDT */
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
new file mode 100644 (file)
index 0000000..841b043
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef _HW_SPAPR_VIO_H
+#define _HW_SPAPR_VIO_H
+/*
+ * QEMU sPAPR VIO bus definitions
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au>
+ * Based on the s390 virtio bus definitions:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * 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/>.
+ */
+
+#define SPAPR_VIO_TCE_PAGE_SHIFT   12
+#define SPAPR_VIO_TCE_PAGE_SIZE    (1ULL << SPAPR_VIO_TCE_PAGE_SHIFT)
+#define SPAPR_VIO_TCE_PAGE_MASK    (SPAPR_VIO_TCE_PAGE_SIZE - 1)
+
+enum VIOsPAPR_TCEAccess {
+    SPAPR_TCE_FAULT = 0,
+    SPAPR_TCE_RO = 1,
+    SPAPR_TCE_WO = 2,
+    SPAPR_TCE_RW = 3,
+};
+
+struct VIOsPAPRDevice;
+
+typedef struct VIOsPAPR_RTCE {
+    uint64_t tce;
+} VIOsPAPR_RTCE;
+
+typedef struct VIOsPAPR_CRQ {
+    uint64_t qladdr;
+    uint32_t qsize;
+    uint32_t qnext;
+    int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
+} VIOsPAPR_CRQ;
+
+typedef struct VIOsPAPRDevice {
+    DeviceState qdev;
+    uint32_t reg;
+    uint32_t flags;
+#define VIO_PAPR_FLAG_DMA_BYPASS        0x1
+    qemu_irq qirq;
+    uint32_t vio_irq_num;
+    target_ulong signal_state;
+    uint32_t rtce_window_size;
+    VIOsPAPR_RTCE *rtce_table;
+    VIOsPAPR_CRQ crq;
+} VIOsPAPRDevice;
+
+typedef struct VIOsPAPRBus {
+    BusState bus;
+} VIOsPAPRBus;
+
+typedef struct {
+    DeviceInfo qdev;
+    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);
+} VIOsPAPRDeviceInfo;
+
+extern VIOsPAPRBus *spapr_vio_bus_init(void);
+extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
+extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
+extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
+
+extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+
+int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
+                         target_ulong len,
+                         enum VIOsPAPR_TCEAccess access);
+
+int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr,
+                       void *buf, uint32_t size);
+int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr,
+                        const void *buf, uint32_t size);
+int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size);
+void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val);
+void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val);
+void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val);
+void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val);
+uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr);
+
+int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
+void spapr_vty_create(VIOsPAPRBus *bus,
+                      uint32_t reg, CharDriverState *chardev,
+                      qemu_irq qirq, uint32_t vio_irq_num);
+
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
+                       qemu_irq qirq, uint32_t vio_irq_num);
+
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
+                        qemu_irq qirq, uint32_t vio_irq_num);
+
+int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
+void spapr_vio_quiesce(void);
+
+#endif /* _HW_SPAPR_VIO_H */
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
new file mode 100644 (file)
index 0000000..9928334
--- /dev/null
@@ -0,0 +1,988 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtual SCSI, aka ibmvscsi
+ *
+ * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation.
+ *
+ * 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.
+ *
+ * TODO:
+ *
+ *  - Cleanups :-)
+ *  - Sort out better how to assign devices to VSCSI instances
+ *  - Fix residual counts
+ *  - Add indirect descriptors support
+ *  - Maybe do autosense (PAPR seems to mandate it, linux doesn't care)
+ */
+#include "hw.h"
+#include "scsi.h"
+#include "scsi-defs.h"
+#include "net.h" /* Remove that when we can */
+#include "srp.h"
+#include "hw/qdev.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+#include "hw/ppc-viosrp.h"
+
+#include <libfdt.h>
+
+/*#define DEBUG_VSCSI*/
+
+#ifdef DEBUG_VSCSI
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+/*
+ * Virtual SCSI device
+ */
+
+/* Random numbers */
+#define VSCSI_MAX_SECTORS       4096
+#define VSCSI_REQ_LIMIT         24
+
+#define SCSI_SENSE_BUF_SIZE     96
+#define SRP_RSP_SENSE_DATA_LEN  18
+
+typedef union vscsi_crq {
+    struct viosrp_crq s;
+    uint8_t raw[16];
+} vscsi_crq;
+
+typedef struct vscsi_req {
+    vscsi_crq               crq;
+    union viosrp_iu         iu;
+
+    /* SCSI request tracking */
+    SCSIDevice              *sdev;
+    uint32_t                qtag; /* qemu tag != srp tag */
+    int                     lun;
+    int                     active;
+    long                    data_len;
+    int                     writing;
+    int                     sensing;
+    int                     senselen;
+    uint8_t                 sense[SCSI_SENSE_BUF_SIZE];
+
+    /* RDMA related bits */
+    uint8_t                 dma_fmt;
+    struct srp_direct_buf   ext_desc;
+    struct srp_direct_buf   *cur_desc;
+    struct srp_indirect_buf *ind_desc;
+    int                     local_desc;
+    int                     total_desc;
+} vscsi_req;
+
+
+typedef struct {
+    VIOsPAPRDevice vdev;
+    SCSIBus bus;
+    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;
+    int i;
+
+    for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
+        req = &s->reqs[i];
+        if (!req->active) {
+            memset(req, 0, sizeof(*req));
+            req->qtag = i;
+            req->active = 1;
+            return req;
+        }
+    }
+    return NULL;
+}
+
+static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
+{
+    req->active = 0;
+}
+
+static vscsi_req *vscsi_find_req(VSCSIState *s, uint32_t tag)
+{
+    if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) {
+        return NULL;
+    }
+    return &s->reqs[tag];
+}
+
+static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
+{
+    /* XXX Figure that one out properly ! This is crackpot */
+    *id = (srp_lun >> 56) & 0x7f;
+    *lun = (srp_lun >> 48) & 0xff;
+}
+
+static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
+                         uint64_t length, uint8_t format)
+{
+    long rc, rc1;
+
+    /* First copy the SRP */
+    rc = spapr_tce_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
+                             &req->iu, length);
+    if (rc) {
+        fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
+    }
+
+    req->crq.s.valid = 0x80;
+    req->crq.s.format = format;
+    req->crq.s.reserved = 0x00;
+    req->crq.s.timeout = cpu_to_be16(0x0000);
+    req->crq.s.IU_length = cpu_to_be16(length);
+    req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
+
+    if (rc == 0) {
+        req->crq.s.status = 0x99; /* Just needs to be non-zero */
+    } else {
+        req->crq.s.status = 0x00;
+    }
+
+    rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
+    if (rc1) {
+        fprintf(stderr, "vscsi_send_iu: Error sending response\n");
+        return rc1;
+    }
+
+    return rc;
+}
+
+static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
+                               uint8_t key, uint8_t asc, uint8_t ascq)
+{
+    req->senselen = SRP_RSP_SENSE_DATA_LEN;
+
+    /* Valid bit and 'current errors' */
+    req->sense[0] = (0x1 << 7 | 0x70);
+    /* Sense key */
+    req->sense[2] = key;
+    /* Additional sense length */
+    req->sense[7] = 0xa; /* 10 bytes */
+    /* Additional sense code */
+    req->sense[12] = asc;
+    req->sense[13] = ascq;
+}
+
+static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
+                          uint8_t status, int32_t res_in, int32_t res_out)
+{
+    union viosrp_iu *iu = &req->iu;
+    uint64_t tag = iu->srp.rsp.tag;
+    int total_len = sizeof(iu->srp.rsp);
+
+    dprintf("VSCSI: Sending resp status: 0x%x, "
+            "res_in: %d, res_out: %d\n", status, res_in, res_out);
+
+    memset(iu, 0, sizeof(struct srp_rsp));
+    iu->srp.rsp.opcode = SRP_RSP;
+    iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
+    iu->srp.rsp.tag = tag;
+
+    /* Handle residuals */
+    if (res_in < 0) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER;
+        res_in = -res_in;
+    } else if (res_in) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
+    }
+    if (res_out < 0) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER;
+        res_out = -res_out;
+    } else if (res_out) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER;
+    }
+    iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in);
+    iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out);
+
+    /* We don't do response data */
+    /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */
+    iu->srp.rsp.resp_data_len = cpu_to_be32(0);
+
+    /* Handle success vs. failure */
+    iu->srp.rsp.status = status;
+    if (status) {
+        iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2;
+        if (req->senselen) {
+            req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+            req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
+            memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
+            total_len += req->senselen;
+        }
+    } else {
+        iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1;
+    }
+
+    vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT);
+    return 0;
+}
+
+static inline void vscsi_swap_desc(struct srp_direct_buf *desc)
+{
+    desc->va = be64_to_cpu(desc->va);
+    desc->len = be32_to_cpu(desc->len);
+}
+
+static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req,
+                                 uint8_t *buf, uint32_t len)
+{
+    struct srp_direct_buf *md = req->cur_desc;
+    uint32_t llen;
+    int rc = 0;
+
+    dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n",
+            len, (unsigned long long)md->va, md->len);
+
+    llen = MIN(len, md->len);
+    if (llen) {
+        if (req->writing) { /* writing = to device = reading from memory */
+            rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen);
+        } else {
+            rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen);
+        }
+    }
+    md->len -= llen;
+    md->va += llen;
+
+    if (rc) {
+        return -1;
+    }
+    return llen;
+}
+
+static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req,
+                                   uint8_t *buf, uint32_t len)
+{
+    struct srp_direct_buf *td = &req->ind_desc->table_desc;
+    struct srp_direct_buf *md = req->cur_desc;
+    int rc = 0;
+    uint32_t llen, total = 0;
+
+    dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n",
+            len, (unsigned long long)td->va, td->len);
+
+    /* While we have data ... */
+    while (len) {
+        /* If we have a descriptor but it's empty, go fetch a new one */
+        if (md && md->len == 0) {
+            /* More local available, use one */
+            if (req->local_desc) {
+                md = ++req->cur_desc;
+                --req->local_desc;
+                --req->total_desc;
+                td->va += sizeof(struct srp_direct_buf);
+            } else {
+                md = req->cur_desc = NULL;
+            }
+        }
+        /* No descriptor at hand, fetch one */
+        if (!md) {
+            if (!req->total_desc) {
+                dprintf("VSCSI:   Out of descriptors !\n");
+                break;
+            }
+            md = req->cur_desc = &req->ext_desc;
+            dprintf("VSCSI:   Reading desc from 0x%llx\n",
+                    (unsigned long long)td->va);
+            rc = spapr_tce_dma_read(&s->vdev, td->va, md,
+                                    sizeof(struct srp_direct_buf));
+            if (rc) {
+                dprintf("VSCSI: tce_dma_read -> %d reading ext_desc\n", rc);
+                break;
+            }
+            vscsi_swap_desc(md);
+            td->va += sizeof(struct srp_direct_buf);
+            --req->total_desc;
+        }
+        dprintf("VSCSI:   [desc va=0x%llx,len=0x%x] remaining=0x%x\n",
+                (unsigned long long)md->va, md->len, len);
+
+        /* Perform transfer */
+        llen = MIN(len, md->len);
+        if (req->writing) { /* writing = to device = reading from memory */
+            rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen);
+        } else {
+            rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen);
+        }
+        if (rc) {
+            dprintf("VSCSI: tce_dma_r/w(%d) -> %d\n", req->writing, rc);
+            break;
+        }
+        dprintf("VSCSI:     data: %02x %02x %02x %02x...\n",
+                buf[0], buf[1], buf[2], buf[3]);
+
+        len -= llen;
+        buf += llen;
+        total += llen;
+        md->va += llen;
+        md->len -= llen;
+    }
+    return rc ? -1 : total;
+}
+
+static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req,
+                                   int writing, uint8_t *buf, uint32_t len)
+{
+    int err = 0;
+
+    switch (req->dma_fmt) {
+    case SRP_NO_DATA_DESC:
+        dprintf("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len);
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        err = vscsi_srp_direct_data(s, req, buf, len);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        err = vscsi_srp_indirect_data(s, req, buf, len);
+        break;
+    }
+    return err;
+}
+
+/* Bits from linux srp */
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+    int size = 0;
+    uint8_t fmt = cmd->buf_fmt >> 4;
+
+    switch (fmt) {
+    case SRP_NO_DATA_DESC:
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        size = sizeof(struct srp_direct_buf);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        size = sizeof(struct srp_indirect_buf) +
+            sizeof(struct srp_direct_buf)*cmd->data_out_desc_cnt;
+        break;
+    default:
+        break;
+    }
+    return size;
+}
+
+static int vscsi_preprocess_desc(vscsi_req *req)
+{
+    struct srp_cmd *cmd = &req->iu.srp.cmd;
+    int offset, i;
+
+    offset = cmd->add_cdb_len & ~3;
+
+    if (req->writing) {
+        req->dma_fmt = cmd->buf_fmt >> 4;
+    } else {
+        offset += data_out_desc_size(cmd);
+        req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1);
+    }
+
+    switch (req->dma_fmt) {
+    case SRP_NO_DATA_DESC:
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset);
+        req->total_desc = req->local_desc = 1;
+        vscsi_swap_desc(req->cur_desc);
+        dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n",
+                req->writing ? "write" : "read",
+                req->cur_desc->len, (unsigned long long)req->cur_desc->va);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset);
+        vscsi_swap_desc(&req->ind_desc->table_desc);
+        req->total_desc = req->ind_desc->table_desc.len /
+            sizeof(struct srp_direct_buf);
+        req->local_desc = req->writing ? cmd->data_out_desc_cnt :
+            cmd->data_in_desc_cnt;
+        for (i = 0; i < req->local_desc; i++) {
+            vscsi_swap_desc(&req->ind_desc->desc_list[i]);
+        }
+        req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL;
+        dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs "
+                "(%d local) VA: 0x%llx\n",
+                req->writing ? "read" : "write",
+                be32_to_cpu(req->ind_desc->len),
+                req->total_desc, req->local_desc,
+                (unsigned long long)req->ind_desc->table_desc.va);
+        break;
+    default:
+        fprintf(stderr,
+                "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
+{
+    SCSIDevice *sdev = req->sdev;
+    uint8_t *cdb = req->iu.srp.cmd.cdb;
+    int n;
+
+    cdb[0] = 3;
+    cdb[1] = 0;
+    cdb[2] = 0;
+    cdb[3] = 0;
+    cdb[4] = 96;
+    cdb[5] = 0;
+    req->sensing = 1;
+    n = sdev->info->send_command(sdev, req->qtag, cdb, req->lun);
+    dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag);
+    if (n < 0) {
+        fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n");
+        sdev->info->cancel_io(sdev, req->qtag);
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        vscsi_put_req(s, req);
+        return;
+    } else if (n == 0) {
+        return;
+    }
+    sdev->info->read_data(sdev, req->qtag);
+}
+
+/* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
+                                   uint32_t arg)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, bus->qbus.parent);
+    vscsi_req *req = vscsi_find_req(s, tag);
+    SCSIDevice *sdev;
+    uint8_t *buf;
+    int32_t res_in = 0, res_out = 0;
+    int len, rc = 0;
+
+    dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n",
+            reason, tag, arg, req);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", tag);
+        return;
+    }
+    sdev = req->sdev;
+
+    if (req->sensing) {
+        if (reason == SCSI_REASON_DONE) {
+            dprintf("VSCSI: Sense done !\n");
+            vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+            vscsi_put_req(s, req);
+        } else {
+            uint8_t *buf = sdev->info->get_buf(sdev, tag);
+
+            len = MIN(arg, SCSI_SENSE_BUF_SIZE);
+            dprintf("VSCSI: Sense data, %d bytes:\n", len);
+            dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                    buf[0], buf[1], buf[2], buf[3],
+                    buf[4], buf[5], buf[6], buf[7]);
+            dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                    buf[8], buf[9], buf[10], buf[11],
+                    buf[12], buf[13], buf[14], buf[15]);
+            memcpy(req->sense, buf, len);
+            req->senselen = len;
+            sdev->info->read_data(sdev, req->qtag);
+        }
+        return;
+    }
+
+    if (reason == SCSI_REASON_DONE) {
+        dprintf("VSCSI: Command complete err=%d\n", arg);
+        if (arg == 0) {
+            /* We handle overflows, not underflows for normal commands,
+             * but hopefully nobody cares
+             */
+            if (req->writing) {
+                res_out = req->data_len;
+            } else {
+                res_in = req->data_len;
+            }
+            vscsi_send_rsp(s, req, 0, res_in, res_out);
+        } else if (arg == CHECK_CONDITION) {
+            dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n");
+            vscsi_send_request_sense(s, req);
+            return;
+        } else {
+            vscsi_send_rsp(s, req, arg, 0, 0);
+        }
+        vscsi_put_req(s, req);
+        return;
+    }
+
+    /* "arg" is how much we have read for reads and how much we want
+     * to write for writes (ie, how much is to be DMA'd)
+     */
+    if (arg) {
+        buf = sdev->info->get_buf(sdev, tag);
+        rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg);
+    }
+    if (rc < 0) {
+        fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
+        sdev->info->cancel_io(sdev, req->qtag);
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        vscsi_put_req(s, req);
+        return;
+    }
+
+    /* Start next chunk */
+    req->data_len -= rc;
+    if (req->writing) {
+        sdev->info->write_data(sdev, req->qtag);
+    } else {
+        sdev->info->read_data(sdev, req->qtag);
+    }
+}
+
+static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
+{
+    union viosrp_iu *iu = &req->iu;
+    struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+    uint64_t tag = iu->srp.rsp.tag;
+
+    dprintf("VSCSI: Got login, sendin response !\n");
+
+    /* TODO handle case that requested size is wrong and
+     * buffer format is wrong
+     */
+    memset(iu, 0, sizeof(struct srp_login_rsp));
+    rsp->opcode = SRP_LOGIN_RSP;
+    /* Don't advertise quite as many request as we support to
+     * keep room for management stuff etc...
+     */
+    rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
+    rsp->tag = tag;
+    rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
+    rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
+    /* direct and indirect */
+    rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
+
+    vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+}
+
+static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
+{
+    uint8_t *cdb = req->iu.srp.cmd.cdb;
+    uint8_t resp_data[36];
+    int rc, len, alen;
+
+    /* We dont do EVPD. Also check that page_code is 0 */
+    if ((cdb[1] & 0x01) || (cdb[1] & 0x01) || cdb[2] != 0) {
+        /* Send INVALID FIELD IN CDB */
+        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        return;
+    }
+    alen = cdb[3];
+    alen = (alen << 8) | cdb[4];
+    len = MIN(alen, 36);
+
+    /* Fake up inquiry using PQ=3 */
+    memset(resp_data, 0, 36);
+    resp_data[0] = 0x7f;   /* Not capable of supporting a device here */
+    resp_data[2] = 0x06;   /* SPS-4 */
+    resp_data[3] = 0x02;   /* Resp data format */
+    resp_data[4] = 36 - 5; /* Additional length */
+    resp_data[7] = 0x10;   /* Sync transfers */
+    memcpy(&resp_data[16], "QEMU EMPTY      ", 16);
+    memcpy(&resp_data[8], "QEMU    ", 8);
+
+    req->writing = 0;
+    vscsi_preprocess_desc(req);
+    rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
+    if (rc < 0) {
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+    } else {
+        vscsi_send_rsp(s, req, 0, 36 - rc, 0);
+    }
+}
+
+static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
+{
+    union srp_iu *srp = &req->iu.srp;
+    SCSIDevice *sdev;
+    int n, id, lun;
+
+    vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun);
+
+    /* Qemu vs. linux issue with LUNs to be sorted out ... */
+    sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL;
+    if (!sdev) {
+        dprintf("VSCSI: Command for id %d with no drive\n", id);
+        if (srp->cmd.cdb[0] == INQUIRY) {
+            vscsi_inquiry_no_target(s, req);
+        } else {
+            vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00);
+            vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        } return 1;
+    }
+
+    req->sdev = sdev;
+    req->lun = lun;
+    n = sdev->info->send_command(sdev, req->qtag, srp->cmd.cdb, lun);
+
+    dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
+            req->qtag, srp->cmd.cdb[0], id, lun, n);
+
+    if (n) {
+        /* Transfer direction must be set before preprocessing the
+         * descriptors
+         */
+        req->writing = (n < 1);
+
+        /* Preprocess RDMA descriptors */
+        vscsi_preprocess_desc(req);
+    }
+
+    /* Get transfer direction and initiate transfer */
+    if (n > 0) {
+        req->data_len = n;
+        sdev->info->read_data(sdev, req->qtag);
+    } else if (n < 0) {
+        req->data_len = -n;
+        sdev->info->write_data(sdev, req->qtag);
+    }
+    /* Don't touch req here, it may have been recycled already */
+
+    return 0;
+}
+
+static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
+{
+    union viosrp_iu *iu = &req->iu;
+    int fn;
+
+    fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
+            iu->srp.tsk_mgmt.tsk_mgmt_func);
+
+    switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
+#if 0 /* We really don't deal with these for now */
+    case SRP_TSK_ABORT_TASK:
+        fn = ABORT_TASK;
+        break;
+    case SRP_TSK_ABORT_TASK_SET:
+        fn = ABORT_TASK_SET;
+        break;
+    case SRP_TSK_CLEAR_TASK_SET:
+        fn = CLEAR_TASK_SET;
+        break;
+    case SRP_TSK_LUN_RESET:
+        fn = LOGICAL_UNIT_RESET;
+        break;
+    case SRP_TSK_CLEAR_ACA:
+        fn = CLEAR_ACA;
+        break;
+#endif
+    default:
+        fn = 0;
+    }
+    if (fn) {
+        /* XXX Send/Handle target task management */
+        ;
+    } else {
+        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x20, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+    }
+    return !fn;
+}
+
+static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
+{
+    union srp_iu *srp = &req->iu.srp;
+    int done = 1;
+    uint8_t opcode = srp->rsp.opcode;
+
+    switch (opcode) {
+    case SRP_LOGIN_REQ:
+        vscsi_process_login(s, req);
+        break;
+    case SRP_TSK_MGMT:
+        done = vscsi_process_tsk_mgmt(s, req);
+        break;
+    case SRP_CMD:
+        done = vscsi_queue_cmd(s, req);
+        break;
+    case SRP_LOGIN_RSP:
+    case SRP_I_LOGOUT:
+    case SRP_T_LOGOUT:
+    case SRP_RSP:
+    case SRP_CRED_REQ:
+    case SRP_CRED_RSP:
+    case SRP_AER_REQ:
+    case SRP_AER_RSP:
+        fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode);
+        break;
+    default:
+        fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode);
+    }
+
+    return done;
+}
+
+static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
+{
+    struct viosrp_adapter_info *sinfo;
+    struct mad_adapter_info_data info;
+    int rc;
+
+    sinfo = &req->iu.mad.adapter_info;
+
+#if 0 /* What for ? */
+    rc = spapr_tce_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
+                            &info, be16_to_cpu(sinfo->common.length));
+    if (rc) {
+        fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n");
+    }
+#endif
+    memset(&info, 0, sizeof(info));
+    strcpy(info.srp_version, SRP_VERSION);
+    strncpy(info.partition_name, "qemu", sizeof("qemu"));
+    info.partition_number = cpu_to_be32(0);
+    info.mad_version = cpu_to_be32(1);
+    info.os_type = cpu_to_be32(2);
+    info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9);
+
+    rc = spapr_tce_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer),
+                             &info, be16_to_cpu(sinfo->common.length));
+    if (rc)  {
+        fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n");
+    }
+
+    sinfo->common.status = rc ? cpu_to_be32(1) : 0;
+
+    return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT);
+}
+
+static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
+{
+    union mad_iu *mad = &req->iu.mad;
+
+    switch (be32_to_cpu(mad->empty_iu.common.type)) {
+    case VIOSRP_EMPTY_IU_TYPE:
+        fprintf(stderr, "Unsupported EMPTY MAD IU\n");
+        break;
+    case VIOSRP_ERROR_LOG_TYPE:
+        fprintf(stderr, "Unsupported ERROR LOG MAD IU\n");
+        mad->error_log.common.status = cpu_to_be16(1);
+        vscsi_send_iu(s, req, sizeof(mad->error_log), VIOSRP_MAD_FORMAT);
+        break;
+    case VIOSRP_ADAPTER_INFO_TYPE:
+        vscsi_send_adapter_info(s, req);
+        break;
+    case VIOSRP_HOST_CONFIG_TYPE:
+        mad->host_config.common.status = cpu_to_be16(1);
+        vscsi_send_iu(s, req, sizeof(mad->host_config), VIOSRP_MAD_FORMAT);
+        break;
+    default:
+        fprintf(stderr, "VSCSI: Unknown MAD type %02x\n",
+                be32_to_cpu(mad->empty_iu.common.type));
+    }
+
+    return 1;
+}
+
+static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
+{
+    vscsi_req *req;
+    int done;
+
+    req = vscsi_get_req(s);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Failed to get a request !\n");
+        return;
+    }
+
+    /* We only support a limited number of descriptors, we know
+     * the ibmvscsi driver uses up to 10 max, so it should fit
+     * in our 256 bytes IUs. If not we'll have to increase the size
+     * of the structure.
+     */
+    if (crq->s.IU_length > sizeof(union viosrp_iu)) {
+        fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
+                crq->s.IU_length);
+        return;
+    }
+
+    /* XXX Handle failure differently ? */
+    if (spapr_tce_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
+                           crq->s.IU_length)) {
+        fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
+        qemu_free(req);
+    }
+    memcpy(&req->crq, crq, sizeof(vscsi_crq));
+
+    if (crq->s.format == VIOSRP_MAD_FORMAT) {
+        done = vscsi_handle_mad_req(s, req);
+    } else {
+        done = vscsi_handle_srp_req(s, req);
+    }
+
+    if (done) {
+        vscsi_put_req(s, req);
+    }
+}
+
+
+static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
+    vscsi_crq crq;
+
+    memcpy(crq.raw, crq_data, 16);
+    crq.s.timeout = be16_to_cpu(crq.s.timeout);
+    crq.s.IU_length = be16_to_cpu(crq.s.IU_length);
+    crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr);
+
+    dprintf("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]);
+
+    switch (crq.s.valid) {
+    case 0xc0: /* Init command/response */
+
+        /* Respond to initialization request */
+        if (crq.s.format == 0x01) {
+            memset(crq.raw, 0, 16);
+            crq.s.valid = 0xc0;
+            crq.s.format = 0x02;
+            spapr_vio_send_crq(dev, crq.raw);
+        }
+
+        /* Note that in hotplug cases, we might get a 0x02
+         * as a result of us emitting the init request
+         */
+
+        break;
+    case 0xff: /* Link event */
+
+        /* Not handled for now */
+
+        break;
+    case 0x80: /* Payloads */
+        switch (crq.s.format) {
+        case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */
+        case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */
+            vscsi_got_payload(s, &crq);
+            break;
+        case VIOSRP_OS400_FORMAT:
+        case VIOSRP_AIX_FORMAT:
+        case VIOSRP_LINUX_FORMAT:
+        case VIOSRP_INLINE_FORMAT:
+            fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n",
+                    crq.s.format);
+            break;
+        default:
+            fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n",
+                    crq.s.format);
+        }
+        break;
+    default:
+        fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n",
+                crq.raw[0], crq.raw[1]);
+    };
+
+    return 0;
+}
+
+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++) {
+        s->reqs[i].qtag = i;
+    }
+
+    dev->crq.SendFunc = vscsi_do_crq;
+
+    scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT,
+                 vscsi_command_complete);
+    if (!dev->qdev.hotplugged) {
+        scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+
+    return 0;
+}
+
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
+                        qemu_irq qirq, uint32_t vio_irq_num)
+{
+    DeviceState *dev;
+    VIOsPAPRDevice *sdev;
+
+    dev = qdev_create(&bus->bus, "spapr-vscsi");
+    qdev_prop_set_uint32(dev, "reg", reg);
+
+    qdev_init_nofail(dev);
+
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
+}
+
+static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    int ret;
+
+    ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static VIOsPAPRDeviceInfo spapr_vscsi = {
+    .init = spapr_vscsi_init,
+    .devnode = spapr_vscsi_devnode,
+    .dt_name = "v-scsi",
+    .dt_type = "vscsi",
+    .dt_compatible = "IBM,v-scsi",
+    .signal_mask = 0x00000001,
+    .qdev.name = "spapr-vscsi",
+    .qdev.size = sizeof(VSCSIState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x2000),
+        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice,
+                           rtce_window_size, 0x10000000),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vscsi_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vscsi);
+}
+device_init(spapr_vscsi_register);
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
new file mode 100644 (file)
index 0000000..6fc0105
--- /dev/null
@@ -0,0 +1,159 @@
+#include "qdev.h"
+#include "qemu-char.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#define VTERM_BUFSIZE   16
+
+typedef struct VIOsPAPRVTYDevice {
+    VIOsPAPRDevice sdev;
+    CharDriverState *chardev;
+    uint32_t in, out;
+    uint8_t buf[VTERM_BUFSIZE];
+} VIOsPAPRVTYDevice;
+
+static int vty_can_receive(void *opaque)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+
+    return (dev->in - dev->out) < VTERM_BUFSIZE;
+}
+
+static void vty_receive(void *opaque, const uint8_t *buf, int size)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+    int i;
+
+    if ((dev->in == dev->out) && size) {
+        /* toggle line to simulate edge interrupt */
+        qemu_irq_pulse(dev->sdev.qirq);
+    }
+    for (i = 0; i < size; i++) {
+        assert((dev->in - dev->out) < VTERM_BUFSIZE);
+        dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
+    }
+}
+
+static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+    int n = 0;
+
+    while ((n < max) && (dev->out != dev->in)) {
+        buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
+    }
+
+    return n;
+}
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    /* FIXME: should check the qemu_chr_write() return value */
+    qemu_chr_write(dev->chardev, buf, len);
+}
+
+static int spapr_vty_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+                          vty_receive, NULL, dev);
+
+    return 0;
+}
+
+static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong len = args[1];
+    target_ulong char0_7 = args[2];
+    target_ulong char8_15 = args[3];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint8_t buf[16];
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    if (len > 16) {
+        return H_PARAMETER;
+    }
+
+    *((uint64_t *)buf) = cpu_to_be64(char0_7);
+    *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
+
+    vty_putchars(sdev, buf, len);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *len = args + 0;
+    target_ulong *char0_7 = args + 1;
+    target_ulong *char8_15 = args + 2;
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint8_t buf[16];
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    *len = vty_getchars(sdev, buf, sizeof(buf));
+    if (*len < 16) {
+        memset(buf + *len, 0, 16 - *len);
+    }
+
+    *char0_7 = be64_to_cpu(*((uint64_t *)buf));
+    *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
+
+    return H_SUCCESS;
+}
+
+void spapr_vty_create(VIOsPAPRBus *bus,
+                      uint32_t reg, CharDriverState *chardev,
+                      qemu_irq qirq, uint32_t vio_irq_num)
+{
+    DeviceState *dev;
+    VIOsPAPRDevice *sdev;
+
+    dev = qdev_create(&bus->bus, "spapr-vty");
+    qdev_prop_set_uint32(dev, "reg", reg);
+    qdev_prop_set_chr(dev, "chardev", chardev);
+    qdev_init_nofail(dev);
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
+}
+
+static void vty_hcalls(VIOsPAPRBus *bus)
+{
+    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
+    spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+}
+
+static VIOsPAPRDeviceInfo spapr_vty = {
+    .init = spapr_vty_init,
+    .dt_name = "vty",
+    .dt_type = "serial",
+    .dt_compatible = "hvterm1",
+    .hcalls = vty_hcalls,
+    .qdev.name = "spapr-vty",
+    .qdev.size = sizeof(VIOsPAPRVTYDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0),
+        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vty_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vty);
+}
+device_init(spapr_vty_register);
diff --git a/hw/srp.h b/hw/srp.h
new file mode 100644 (file)
index 0000000..afcd135
--- /dev/null
+++ b/hw/srp.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * 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 SCSI_SRP_H
+#define SCSI_SRP_H
+
+/*
+ * Structures and constants for the SCSI RDMA Protocol (SRP) as
+ * defined by the INCITS T10 committee.  This file was written using
+ * draft Revision 16a of the SRP standard.
+ */
+
+enum {
+
+    SRP_LOGIN_REQ = 0x00,
+    SRP_TSK_MGMT  = 0x01,
+    SRP_CMD       = 0x02,
+    SRP_I_LOGOUT  = 0x03,
+    SRP_LOGIN_RSP = 0xc0,
+    SRP_RSP       = 0xc1,
+    SRP_LOGIN_REJ = 0xc2,
+    SRP_T_LOGOUT  = 0x80,
+    SRP_CRED_REQ  = 0x81,
+    SRP_AER_REQ   = 0x82,
+    SRP_CRED_RSP  = 0x41,
+    SRP_AER_RSP   = 0x42
+};
+
+enum {
+    SRP_BUF_FORMAT_DIRECT   = 1 << 1,
+    SRP_BUF_FORMAT_INDIRECT = 1 << 2
+};
+
+enum {
+    SRP_NO_DATA_DESC       = 0,
+    SRP_DATA_DESC_DIRECT   = 1,
+    SRP_DATA_DESC_INDIRECT = 2
+};
+
+enum {
+    SRP_TSK_ABORT_TASK     = 0x01,
+    SRP_TSK_ABORT_TASK_SET = 0x02,
+    SRP_TSK_CLEAR_TASK_SET = 0x04,
+    SRP_TSK_LUN_RESET      = 0x08,
+    SRP_TSK_CLEAR_ACA      = 0x40
+};
+
+enum srp_login_rej_reason {
+    SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL   = 0x00010000,
+    SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES     = 0x00010001,
+    SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
+    SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL   = 0x00010003,
+    SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
+    SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED  = 0x00010005,
+    SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED      = 0x00010006
+};
+
+enum {
+    SRP_REV10_IB_IO_CLASS  = 0xff00,
+    SRP_REV16A_IB_IO_CLASS = 0x0100
+};
+
+struct srp_direct_buf {
+    uint64_t    va;
+    uint32_t    key;
+    uint32_t    len;
+};
+
+/*
+ * We need the packed attribute because the SRP spec puts the list of
+ * descriptors at an offset of 20, which is not aligned to the size of
+ * struct srp_direct_buf.  The whole structure must be packed to avoid
+ * having the 20-byte structure padded to 24 bytes on 64-bit architectures.
+ */
+struct srp_indirect_buf {
+    struct srp_direct_buf    table_desc;
+    uint32_t                 len;
+    struct srp_direct_buf    desc_list[0];
+} __attribute__((packed));
+
+enum {
+    SRP_MULTICHAN_SINGLE = 0,
+    SRP_MULTICHAN_MULTI  = 1
+};
+
+struct srp_login_req {
+    uint8_t    opcode;
+    uint8_t    reserved1[7];
+    uint64_t   tag;
+    uint32_t   req_it_iu_len;
+    uint8_t    reserved2[4];
+    uint16_t   req_buf_fmt;
+    uint8_t    req_flags;
+    uint8_t    reserved3[5];
+    uint8_t    initiator_port_id[16];
+    uint8_t    target_port_id[16];
+};
+
+/*
+ * The SRP spec defines the size of the LOGIN_RSP structure to be 52
+ * bytes, so it needs to be packed to avoid having it padded to 56
+ * bytes on 64-bit architectures.
+ */
+struct srp_login_rsp {
+    uint8_t    opcode;
+    uint8_t    reserved1[3];
+    uint32_t   req_lim_delta;
+    uint64_t   tag;
+    uint32_t   max_it_iu_len;
+    uint32_t   max_ti_iu_len;
+    uint16_t   buf_fmt;
+    uint8_t    rsp_flags;
+    uint8_t    reserved2[25];
+} __attribute__((packed));
+
+struct srp_login_rej {
+    uint8_t    opcode;
+    uint8_t    reserved1[3];
+    uint32_t   reason;
+    uint64_t   tag;
+    uint8_t    reserved2[8];
+    uint16_t   buf_fmt;
+    uint8_t    reserved3[6];
+};
+
+struct srp_i_logout {
+    uint8_t    opcode;
+    uint8_t    reserved[7];
+    uint64_t   tag;
+};
+
+struct srp_t_logout {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved[2];
+    uint32_t   reason;
+    uint64_t   tag;
+};
+
+/*
+ * We need the packed attribute because the SRP spec only aligns the
+ * 8-byte LUN field to 4 bytes.
+ */
+struct srp_tsk_mgmt {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[6];
+    uint64_t   tag;
+    uint8_t    reserved2[4];
+    uint64_t   lun __attribute__((packed));
+    uint8_t    reserved3[2];
+    uint8_t    tsk_mgmt_func;
+    uint8_t    reserved4;
+    uint64_t   task_tag;
+    uint8_t    reserved5[8];
+};
+
+/*
+ * We need the packed attribute because the SRP spec only aligns the
+ * 8-byte LUN field to 4 bytes.
+ */
+struct srp_cmd {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[3];
+    uint8_t    buf_fmt;
+    uint8_t    data_out_desc_cnt;
+    uint8_t    data_in_desc_cnt;
+    uint64_t   tag;
+    uint8_t    reserved2[4];
+    uint64_t   lun __attribute__((packed));
+    uint8_t    reserved3;
+    uint8_t    task_attr;
+    uint8_t    reserved4;
+    uint8_t    add_cdb_len;
+    uint8_t    cdb[16];
+    uint8_t    add_data[0];
+};
+
+enum {
+    SRP_RSP_FLAG_RSPVALID = 1 << 0,
+    SRP_RSP_FLAG_SNSVALID = 1 << 1,
+    SRP_RSP_FLAG_DOOVER   = 1 << 2,
+    SRP_RSP_FLAG_DOUNDER  = 1 << 3,
+    SRP_RSP_FLAG_DIOVER   = 1 << 4,
+    SRP_RSP_FLAG_DIUNDER  = 1 << 5
+};
+
+/*
+ * The SRP spec defines the size of the RSP structure to be 36 bytes,
+ * so it needs to be packed to avoid having it padded to 40 bytes on
+ * 64-bit architectures.
+ */
+struct srp_rsp {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[2];
+    uint32_t   req_lim_delta;
+    uint64_t   tag;
+    uint8_t    reserved2[2];
+    uint8_t    flags;
+    uint8_t    status;
+    uint32_t   data_out_res_cnt;
+    uint32_t   data_in_res_cnt;
+    uint32_t   sense_data_len;
+    uint32_t   resp_data_len;
+    uint8_t    data[0];
+} __attribute__((packed));
+
+#endif /* SCSI_SRP_H */
index 0d5292688e530b3f96ee9469e07ee495c5939c9f..ac9fcc1f38d54ee83d6b45a6644ef49ec73d5946 100644 (file)
@@ -14,7 +14,6 @@
 #include "qemu-timer.h"
 #include "i2c.h"
 #include "net.h"
-#include "sysemu.h"
 #include "boards.h"
 
 #define GPIO_A 0
@@ -280,64 +279,28 @@ static CPUWriteMemoryFunc * const gptm_writefn[] = {
    gptm_write
 };
 
-static void gptm_save(QEMUFile *f, void *opaque)
-{
-    gptm_state *s = (gptm_state *)opaque;
-
-    qemu_put_be32(f, s->config);
-    qemu_put_be32(f, s->mode[0]);
-    qemu_put_be32(f, s->mode[1]);
-    qemu_put_be32(f, s->control);
-    qemu_put_be32(f, s->state);
-    qemu_put_be32(f, s->mask);
-    qemu_put_be32(f, s->mode[0]);
-    qemu_put_be32(f, s->mode[0]);
-    qemu_put_be32(f, s->load[0]);
-    qemu_put_be32(f, s->load[1]);
-    qemu_put_be32(f, s->match[0]);
-    qemu_put_be32(f, s->match[1]);
-    qemu_put_be32(f, s->prescale[0]);
-    qemu_put_be32(f, s->prescale[1]);
-    qemu_put_be32(f, s->match_prescale[0]);
-    qemu_put_be32(f, s->match_prescale[1]);
-    qemu_put_be32(f, s->rtc);
-    qemu_put_be64(f, s->tick[0]);
-    qemu_put_be64(f, s->tick[1]);
-    qemu_put_timer(f, s->timer[0]);
-    qemu_put_timer(f, s->timer[1]);
-}
-
-static int gptm_load(QEMUFile *f, void *opaque, int version_id)
-{
-    gptm_state *s = (gptm_state *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->config = qemu_get_be32(f);
-    s->mode[0] = qemu_get_be32(f);
-    s->mode[1] = qemu_get_be32(f);
-    s->control = qemu_get_be32(f);
-    s->state = qemu_get_be32(f);
-    s->mask = qemu_get_be32(f);
-    s->mode[0] = qemu_get_be32(f);
-    s->mode[0] = qemu_get_be32(f);
-    s->load[0] = qemu_get_be32(f);
-    s->load[1] = qemu_get_be32(f);
-    s->match[0] = qemu_get_be32(f);
-    s->match[1] = qemu_get_be32(f);
-    s->prescale[0] = qemu_get_be32(f);
-    s->prescale[1] = qemu_get_be32(f);
-    s->match_prescale[0] = qemu_get_be32(f);
-    s->match_prescale[1] = qemu_get_be32(f);
-    s->rtc = qemu_get_be32(f);
-    s->tick[0] = qemu_get_be64(f);
-    s->tick[1] = qemu_get_be64(f);
-    qemu_get_timer(f, s->timer[0]);
-    qemu_get_timer(f, s->timer[1]);
-
-    return 0;
-}
+static const VMStateDescription vmstate_stellaris_gptm = {
+    .name = "stellaris_gptm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(config, gptm_state),
+        VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
+        VMSTATE_UINT32(control, gptm_state),
+        VMSTATE_UINT32(state, gptm_state),
+        VMSTATE_UINT32(mask, gptm_state),
+        VMSTATE_UNUSED(8),
+        VMSTATE_UINT32_ARRAY(load, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(match, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2),
+        VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
+        VMSTATE_UINT32(rtc, gptm_state),
+        VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
+        VMSTATE_TIMER_ARRAY(timer, gptm_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int stellaris_gptm_init(SysBusDevice *dev)
 {
@@ -355,8 +318,7 @@ static int stellaris_gptm_init(SysBusDevice *dev)
     s->opaque[0] = s->opaque[1] = s;
     s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]);
     s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]);
-    register_savevm(&dev->qdev, "stellaris_gptm", -1, 1,
-                    gptm_save, gptm_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s);
     return 0;
 }
 
@@ -605,58 +567,37 @@ static void ssys_reset(void *opaque)
     s->dcgc[0] = 1;
 }
 
-static void ssys_save(QEMUFile *f, void *opaque)
-{
-    ssys_state *s = (ssys_state *)opaque;
-
-    qemu_put_be32(f, s->pborctl);
-    qemu_put_be32(f, s->ldopctl);
-    qemu_put_be32(f, s->int_mask);
-    qemu_put_be32(f, s->int_status);
-    qemu_put_be32(f, s->resc);
-    qemu_put_be32(f, s->rcc);
-    qemu_put_be32(f, s->rcgc[0]);
-    qemu_put_be32(f, s->rcgc[1]);
-    qemu_put_be32(f, s->rcgc[2]);
-    qemu_put_be32(f, s->scgc[0]);
-    qemu_put_be32(f, s->scgc[1]);
-    qemu_put_be32(f, s->scgc[2]);
-    qemu_put_be32(f, s->dcgc[0]);
-    qemu_put_be32(f, s->dcgc[1]);
-    qemu_put_be32(f, s->dcgc[2]);
-    qemu_put_be32(f, s->clkvclr);
-    qemu_put_be32(f, s->ldoarst);
-}
-
-static int ssys_load(QEMUFile *f, void *opaque, int version_id)
+static int stellaris_sys_post_load(void *opaque, int version_id)
 {
-    ssys_state *s = (ssys_state *)opaque;
+    ssys_state *s = opaque;
 
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->pborctl = qemu_get_be32(f);
-    s->ldopctl = qemu_get_be32(f);
-    s->int_mask = qemu_get_be32(f);
-    s->int_status = qemu_get_be32(f);
-    s->resc = qemu_get_be32(f);
-    s->rcc = qemu_get_be32(f);
-    s->rcgc[0] = qemu_get_be32(f);
-    s->rcgc[1] = qemu_get_be32(f);
-    s->rcgc[2] = qemu_get_be32(f);
-    s->scgc[0] = qemu_get_be32(f);
-    s->scgc[1] = qemu_get_be32(f);
-    s->scgc[2] = qemu_get_be32(f);
-    s->dcgc[0] = qemu_get_be32(f);
-    s->dcgc[1] = qemu_get_be32(f);
-    s->dcgc[2] = qemu_get_be32(f);
-    s->clkvclr = qemu_get_be32(f);
-    s->ldoarst = qemu_get_be32(f);
     ssys_calculate_system_clock(s);
 
     return 0;
 }
 
+static const VMStateDescription vmstate_stellaris_sys = {
+    .name = "stellaris_sys",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = stellaris_sys_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(pborctl, ssys_state),
+        VMSTATE_UINT32(ldopctl, ssys_state),
+        VMSTATE_UINT32(int_mask, ssys_state),
+        VMSTATE_UINT32(int_status, ssys_state),
+        VMSTATE_UINT32(resc, ssys_state),
+        VMSTATE_UINT32(rcc, ssys_state),
+        VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
+        VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
+        VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
+        VMSTATE_UINT32(clkvclr, ssys_state),
+        VMSTATE_UINT32(ldoarst, ssys_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static int stellaris_sys_init(uint32_t base, qemu_irq irq,
                               stellaris_board_info * board,
                               uint8_t *macaddr)
@@ -676,7 +617,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq,
                                        DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00001000, iomemtype);
     ssys_reset(s);
-    register_savevm(NULL, "stellaris_sys", -1, 1, ssys_save, ssys_load, s);
+    vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
     return 0;
 }
 
@@ -844,36 +785,22 @@ static CPUWriteMemoryFunc * const stellaris_i2c_writefn[] = {
    stellaris_i2c_write
 };
 
-static void stellaris_i2c_save(QEMUFile *f, void *opaque)
-{
-    stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
-
-    qemu_put_be32(f, s->msa);
-    qemu_put_be32(f, s->mcs);
-    qemu_put_be32(f, s->mdr);
-    qemu_put_be32(f, s->mtpr);
-    qemu_put_be32(f, s->mimr);
-    qemu_put_be32(f, s->mris);
-    qemu_put_be32(f, s->mcr);
-}
-
-static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id)
-{
-    stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->msa = qemu_get_be32(f);
-    s->mcs = qemu_get_be32(f);
-    s->mdr = qemu_get_be32(f);
-    s->mtpr = qemu_get_be32(f);
-    s->mimr = qemu_get_be32(f);
-    s->mris = qemu_get_be32(f);
-    s->mcr = qemu_get_be32(f);
-
-    return 0;
-}
+static const VMStateDescription vmstate_stellaris_i2c = {
+    .name = "stellaris_i2c",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(msa, stellaris_i2c_state),
+        VMSTATE_UINT32(mcs, stellaris_i2c_state),
+        VMSTATE_UINT32(mdr, stellaris_i2c_state),
+        VMSTATE_UINT32(mtpr, stellaris_i2c_state),
+        VMSTATE_UINT32(mimr, stellaris_i2c_state),
+        VMSTATE_UINT32(mris, stellaris_i2c_state),
+        VMSTATE_UINT32(mcr, stellaris_i2c_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int stellaris_i2c_init(SysBusDevice * dev)
 {
@@ -891,8 +818,7 @@ static int stellaris_i2c_init(SysBusDevice * dev)
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     /* ??? For now we only implement the master interface.  */
     stellaris_i2c_reset(s);
-    register_savevm(&dev->qdev, "stellaris_i2c", -1, 1,
-                    stellaris_i2c_save, stellaris_i2c_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s);
     return 0;
 }
 
@@ -1130,60 +1056,40 @@ static CPUWriteMemoryFunc * const stellaris_adc_writefn[] = {
    stellaris_adc_write
 };
 
-static void stellaris_adc_save(QEMUFile *f, void *opaque)
-{
-    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
-    int i;
-    int j;
-
-    qemu_put_be32(f, s->actss);
-    qemu_put_be32(f, s->ris);
-    qemu_put_be32(f, s->im);
-    qemu_put_be32(f, s->emux);
-    qemu_put_be32(f, s->ostat);
-    qemu_put_be32(f, s->ustat);
-    qemu_put_be32(f, s->sspri);
-    qemu_put_be32(f, s->sac);
-    for (i = 0; i < 4; i++) {
-        qemu_put_be32(f, s->fifo[i].state);
-        for (j = 0; j < 16; j++) {
-            qemu_put_be32(f, s->fifo[i].data[j]);
-        }
-        qemu_put_be32(f, s->ssmux[i]);
-        qemu_put_be32(f, s->ssctl[i]);
-    }
-    qemu_put_be32(f, s->noise);
-}
-
-static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id)
-{
-    stellaris_adc_state *s = (stellaris_adc_state *)opaque;
-    int i;
-    int j;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->actss = qemu_get_be32(f);
-    s->ris = qemu_get_be32(f);
-    s->im = qemu_get_be32(f);
-    s->emux = qemu_get_be32(f);
-    s->ostat = qemu_get_be32(f);
-    s->ustat = qemu_get_be32(f);
-    s->sspri = qemu_get_be32(f);
-    s->sac = qemu_get_be32(f);
-    for (i = 0; i < 4; i++) {
-        s->fifo[i].state = qemu_get_be32(f);
-        for (j = 0; j < 16; j++) {
-            s->fifo[i].data[j] = qemu_get_be32(f);
-        }
-        s->ssmux[i] = qemu_get_be32(f);
-        s->ssctl[i] = qemu_get_be32(f);
+static const VMStateDescription vmstate_stellaris_adc = {
+    .name = "stellaris_adc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(actss, stellaris_adc_state),
+        VMSTATE_UINT32(ris, stellaris_adc_state),
+        VMSTATE_UINT32(im, stellaris_adc_state),
+        VMSTATE_UINT32(emux, stellaris_adc_state),
+        VMSTATE_UINT32(ostat, stellaris_adc_state),
+        VMSTATE_UINT32(ustat, stellaris_adc_state),
+        VMSTATE_UINT32(sspri, stellaris_adc_state),
+        VMSTATE_UINT32(sac, stellaris_adc_state),
+        VMSTATE_UINT32(fifo[0].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[0], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[0], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[1].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[1], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[1], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[2].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[2], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[2], stellaris_adc_state),
+        VMSTATE_UINT32(fifo[3].state, stellaris_adc_state),
+        VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16),
+        VMSTATE_UINT32(ssmux[3], stellaris_adc_state),
+        VMSTATE_UINT32(ssctl[3], stellaris_adc_state),
+        VMSTATE_UINT32(noise, stellaris_adc_state),
+        VMSTATE_END_OF_LIST()
     }
-    s->noise = qemu_get_be32(f);
-
-    return 0;
-}
+};
 
 static int stellaris_adc_init(SysBusDevice *dev)
 {
@@ -1201,8 +1107,7 @@ static int stellaris_adc_init(SysBusDevice *dev)
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     stellaris_adc_reset(s);
     qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
-    register_savevm(&dev->qdev, "stellaris_adc", -1, 1,
-                    stellaris_adc_save, stellaris_adc_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s);
     return 0;
 }
 
@@ -1234,24 +1139,16 @@ static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
     return ssi_transfer(s->bus[s->current_dev], val);
 }
 
-static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque)
-{
-    stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
-
-    qemu_put_be32(f, s->current_dev);
-}
-
-static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id)
-{
-    stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->current_dev = qemu_get_be32(f);
-
-    return 0;
-}
+static const VMStateDescription vmstate_stellaris_ssi_bus = {
+    .name = "stellaris_ssi_bus",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(current_dev, stellaris_ssi_bus_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int stellaris_ssi_bus_init(SSISlave *dev)
 {
@@ -1261,8 +1158,7 @@ static int stellaris_ssi_bus_init(SSISlave *dev)
     s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
     qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
 
-    register_savevm(&dev->qdev, "stellaris_ssi_bus", -1, 1,
-                    stellaris_ssi_bus_save, stellaris_ssi_bus_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s);
     return 0;
 }
 
index 16aae96f2f563b08b8d409bec29ecb093c267728..06c5f9d9559de71f1ca8d0912c02bf0bb5942dcd 100644 (file)
@@ -13,7 +13,7 @@
 typedef struct {
     qemu_irq irq;
     int keycode;
-    int pressed;
+    uint8_t pressed;
 } gamepad_button;
 
 typedef struct {
@@ -47,30 +47,29 @@ static void stellaris_gamepad_put_key(void * opaque, int keycode)
     s->extension = 0;
 }
 
-static void stellaris_gamepad_save(QEMUFile *f, void *opaque)
-{
-    gamepad_state *s = (gamepad_state *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->extension);
-    for (i = 0; i < s->num_buttons; i++)
-        qemu_put_byte(f, s->buttons[i].pressed);
-}
-
-static int stellaris_gamepad_load(QEMUFile *f, void *opaque, int version_id)
-{
-    gamepad_state *s = (gamepad_state *)opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->extension = qemu_get_be32(f);
-    for (i = 0; i < s->num_buttons; i++)
-        s->buttons[i].pressed = qemu_get_byte(f);
+static const VMStateDescription vmstate_stellaris_button = {
+    .name = "stellaris_button",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(pressed, gamepad_button),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-    return 0;
-}
+static const VMStateDescription vmstate_stellaris_gamepad = {
+    .name = "stellaris_gamepad",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(extension, gamepad_state),
+        VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0,
+                              vmstate_stellaris_button, gamepad_button),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 /* Returns an array 5 ouput slots.  */
 void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
@@ -86,6 +85,5 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
     }
     s->num_buttons = n;
     qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
-    register_savevm(NULL, "stellaris_gamepad", -1, 1,
-                    stellaris_gamepad_save, stellaris_gamepad_load, s);
+    vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s);
 }
diff --git a/hw/strongarm.c b/hw/strongarm.c
new file mode 100644 (file)
index 0000000..de08bdf
--- /dev/null
@@ -0,0 +1,1598 @@
+/*
+ * StrongARM SA-1100/SA-1110 emulation
+ *
+ * Copyright (C) 2011 Dmitry Eremin-Solenikov
+ *
+ * Largely based on StrongARM emulation:
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * UART code based on QEMU 16550A UART emulation
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ *  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.
+ *
+ *  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 "sysbus.h"
+#include "strongarm.h"
+#include "qemu-error.h"
+#include "arm-misc.h"
+#include "sysemu.h"
+#include "ssi.h"
+
+//#define DEBUG
+
+/*
+ TODO
+ - Implement cp15, c14 ?
+ - Implement cp15, c15 !!! (idle used in L)
+ - Implement idle mode handling/DIM
+ - Implement sleep mode/Wake sources
+ - Implement reset control
+ - Implement memory control regs
+ - PCMCIA handling
+ - Maybe support MBGNT/MBREQ
+ - DMA channels
+ - GPCLK
+ - IrDA
+ - MCP
+ - Enhance UART with modem signals
+ */
+
+#ifdef DEBUG
+# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__)
+#else
+# define DPRINTF(format, ...) do { } while (0)
+#endif
+
+static struct {
+    target_phys_addr_t io_base;
+    int irq;
+} sa_serial[] = {
+    { 0x80010000, SA_PIC_UART1 },
+    { 0x80030000, SA_PIC_UART2 },
+    { 0x80050000, SA_PIC_UART3 },
+    { 0, 0 }
+};
+
+/* Interrupt Controller */
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq    irq;
+    qemu_irq    fiq;
+
+    uint32_t pending;
+    uint32_t enabled;
+    uint32_t is_fiq;
+    uint32_t int_idle;
+} StrongARMPICState;
+
+#define ICIP    0x00
+#define ICMR    0x04
+#define ICLR    0x08
+#define ICFP    0x10
+#define ICPR    0x20
+#define ICCR    0x0c
+
+#define SA_PIC_SRCS     32
+
+
+static void strongarm_pic_update(void *opaque)
+{
+    StrongARMPICState *s = opaque;
+
+    /* FIXME: reflect DIM */
+    qemu_set_irq(s->fiq, s->pending & s->enabled &  s->is_fiq);
+    qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq);
+}
+
+static void strongarm_pic_set_irq(void *opaque, int irq, int level)
+{
+    StrongARMPICState *s = opaque;
+
+    if (level) {
+        s->pending |= 1 << irq;
+    } else {
+        s->pending &= ~(1 << irq);
+    }
+
+    strongarm_pic_update(s);
+}
+
+static uint32_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset)
+{
+    StrongARMPICState *s = opaque;
+
+    switch (offset) {
+    case ICIP:
+        return s->pending & ~s->is_fiq & s->enabled;
+    case ICMR:
+        return s->enabled;
+    case ICLR:
+        return s->is_fiq;
+    case ICCR:
+        return s->int_idle == 0;
+    case ICFP:
+        return s->pending & s->is_fiq & s->enabled;
+    case ICPR:
+        return s->pending;
+    default:
+        printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return 0;
+    }
+}
+
+static void strongarm_pic_mem_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    StrongARMPICState *s = opaque;
+
+    switch (offset) {
+    case ICMR:
+        s->enabled = value;
+        break;
+    case ICLR:
+        s->is_fiq = value;
+        break;
+    case ICCR:
+        s->int_idle = (value & 1) ? 0 : ~0;
+        break;
+    default:
+        printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        break;
+    }
+    strongarm_pic_update(s);
+}
+
+static CPUReadMemoryFunc * const strongarm_pic_readfn[] = {
+    strongarm_pic_mem_read,
+    strongarm_pic_mem_read,
+    strongarm_pic_mem_read,
+};
+
+static CPUWriteMemoryFunc * const strongarm_pic_writefn[] = {
+    strongarm_pic_mem_write,
+    strongarm_pic_mem_write,
+    strongarm_pic_mem_write,
+};
+
+static int strongarm_pic_initfn(SysBusDevice *dev)
+{
+    StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev);
+    int iomemtype;
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS);
+    iomemtype = cpu_register_io_memory(strongarm_pic_readfn,
+                    strongarm_pic_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fiq);
+
+    return 0;
+}
+
+static int strongarm_pic_post_load(void *opaque, int version_id)
+{
+    strongarm_pic_update(opaque);
+    return 0;
+}
+
+static VMStateDescription vmstate_strongarm_pic_regs = {
+    .name = "strongarm_pic",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_pic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(pending, StrongARMPICState),
+        VMSTATE_UINT32(enabled, StrongARMPICState),
+        VMSTATE_UINT32(is_fiq, StrongARMPICState),
+        VMSTATE_UINT32(int_idle, StrongARMPICState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_pic_info = {
+    .init       = strongarm_pic_initfn,
+    .qdev.name  = "strongarm_pic",
+    .qdev.desc  = "StrongARM PIC",
+    .qdev.size  = sizeof(StrongARMPICState),
+    .qdev.vmsd  = &vmstate_strongarm_pic_regs,
+};
+
+/* Real-Time Clock */
+#define RTAR 0x00 /* RTC Alarm register */
+#define RCNR 0x04 /* RTC Counter register */
+#define RTTR 0x08 /* RTC Timer Trim register */
+#define RTSR 0x10 /* RTC Status register */
+
+#define RTSR_AL (1 << 0) /* RTC Alarm detected */
+#define RTSR_HZ (1 << 1) /* RTC 1Hz detected */
+#define RTSR_ALE (1 << 2) /* RTC Alarm enable */
+#define RTSR_HZE (1 << 3) /* RTC 1Hz enable */
+
+/* 16 LSB of RTTR are clockdiv for internal trim logic,
+ * trim delete isn't emulated, so
+ * f = 32 768 / (RTTR_trim + 1) */
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t rttr;
+    uint32_t rtsr;
+    uint32_t rtar;
+    uint32_t last_rcnr;
+    int64_t last_hz;
+    QEMUTimer *rtc_alarm;
+    QEMUTimer *rtc_hz;
+    qemu_irq rtc_irq;
+    qemu_irq rtc_hz_irq;
+} StrongARMRTCState;
+
+static inline void strongarm_rtc_int_update(StrongARMRTCState *s)
+{
+    qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL);
+    qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ);
+}
+
+static void strongarm_rtc_hzupdate(StrongARMRTCState *s)
+{
+    int64_t rt = qemu_get_clock_ms(rt_clock);
+    s->last_rcnr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_hz = rt;
+}
+
+static inline void strongarm_rtc_timer_update(StrongARMRTCState *s)
+{
+    if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) {
+        qemu_mod_timer(s->rtc_hz, s->last_hz + 1000);
+    } else {
+        qemu_del_timer(s->rtc_hz);
+    }
+
+    if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) {
+        qemu_mod_timer(s->rtc_alarm, s->last_hz +
+                (((s->rtar - s->last_rcnr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15));
+    } else {
+        qemu_del_timer(s->rtc_alarm);
+    }
+}
+
+static inline void strongarm_rtc_alarm_tick(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+    s->rtsr |= RTSR_AL;
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+}
+
+static inline void strongarm_rtc_hz_tick(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+    s->rtsr |= RTSR_HZ;
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+}
+
+static uint32_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr)
+{
+    StrongARMRTCState *s = opaque;
+
+    switch (addr) {
+    case RTTR:
+        return s->rttr;
+    case RTSR:
+        return s->rtsr;
+    case RTAR:
+        return s->rtar;
+    case RCNR:
+        return s->last_rcnr +
+                ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        return 0;
+    }
+}
+
+static void strongarm_rtc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    StrongARMRTCState *s = opaque;
+    uint32_t old_rtsr;
+
+    switch (addr) {
+    case RTTR:
+        strongarm_rtc_hzupdate(s);
+        s->rttr = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    case RTSR:
+        old_rtsr = s->rtsr;
+        s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) |
+                  (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ)));
+
+        if (s->rtsr != old_rtsr) {
+            strongarm_rtc_timer_update(s);
+        }
+
+        strongarm_rtc_int_update(s);
+        break;
+
+    case RTAR:
+        s->rtar = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    case RCNR:
+        strongarm_rtc_hzupdate(s);
+        s->last_rcnr = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_rtc_readfn[] = {
+    strongarm_rtc_read,
+    strongarm_rtc_read,
+    strongarm_rtc_read,
+};
+
+static CPUWriteMemoryFunc * const strongarm_rtc_writefn[] = {
+    strongarm_rtc_write,
+    strongarm_rtc_write,
+    strongarm_rtc_write,
+};
+
+static int strongarm_rtc_init(SysBusDevice *dev)
+{
+    StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev);
+    struct tm tm;
+    int iomemtype;
+
+    s->rttr = 0x0;
+    s->rtsr = 0;
+
+    qemu_get_timedate(&tm, 0);
+
+    s->last_rcnr = (uint32_t) mktimegm(&tm);
+    s->last_hz = qemu_get_clock_ms(rt_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);
+
+    sysbus_init_irq(dev, &s->rtc_irq);
+    sysbus_init_irq(dev, &s->rtc_hz_irq);
+
+    iomemtype = cpu_register_io_memory(strongarm_rtc_readfn,
+                    strongarm_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x10000, iomemtype);
+
+    return 0;
+}
+
+static void strongarm_rtc_pre_save(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+
+    strongarm_rtc_hzupdate(s);
+}
+
+static int strongarm_rtc_post_load(void *opaque, int version_id)
+{
+    StrongARMRTCState *s = opaque;
+
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_rtc_regs = {
+    .name = "strongarm-rtc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = strongarm_rtc_pre_save,
+    .post_load = strongarm_rtc_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(rttr, StrongARMRTCState),
+        VMSTATE_UINT32(rtsr, StrongARMRTCState),
+        VMSTATE_UINT32(rtar, StrongARMRTCState),
+        VMSTATE_UINT32(last_rcnr, StrongARMRTCState),
+        VMSTATE_INT64(last_hz, StrongARMRTCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_rtc_sysbus_info = {
+    .init       = strongarm_rtc_init,
+    .qdev.name  = "strongarm-rtc",
+    .qdev.desc  = "StrongARM RTC Controller",
+    .qdev.size  = sizeof(StrongARMRTCState),
+    .qdev.vmsd  = &vmstate_strongarm_rtc_regs,
+};
+
+/* GPIO */
+#define GPLR 0x00
+#define GPDR 0x04
+#define GPSR 0x08
+#define GPCR 0x0c
+#define GRER 0x10
+#define GFER 0x14
+#define GEDR 0x18
+#define GAFR 0x1c
+
+typedef struct StrongARMGPIOInfo StrongARMGPIOInfo;
+struct StrongARMGPIOInfo {
+    SysBusDevice busdev;
+    qemu_irq handler[28];
+    qemu_irq irqs[11];
+    qemu_irq irqX;
+
+    uint32_t ilevel;
+    uint32_t olevel;
+    uint32_t dir;
+    uint32_t rising;
+    uint32_t falling;
+    uint32_t status;
+    uint32_t gpsr;
+    uint32_t gafr;
+
+    uint32_t prev_level;
+};
+
+
+static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s)
+{
+    int i;
+    for (i = 0; i < 11; i++) {
+        qemu_set_irq(s->irqs[i], s->status & (1 << i));
+    }
+
+    qemu_set_irq(s->irqX, (s->status & ~0x7ff));
+}
+
+static void strongarm_gpio_set(void *opaque, int line, int level)
+{
+    StrongARMGPIOInfo *s = opaque;
+    uint32_t mask;
+
+    mask = 1 << line;
+
+    if (level) {
+        s->status |= s->rising & mask &
+                ~s->ilevel & ~s->dir;
+        s->ilevel |= mask;
+    } else {
+        s->status |= s->falling & mask &
+                s->ilevel & ~s->dir;
+        s->ilevel &= ~mask;
+    }
+
+    if (s->status & mask) {
+        strongarm_gpio_irq_update(s);
+    }
+}
+
+static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->olevel & s->dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+static uint32_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset)
+{
+    StrongARMGPIOInfo *s = opaque;
+
+    switch (offset) {
+    case GPDR:        /* GPIO Pin-Direction registers */
+        return s->dir;
+
+    case GPSR:        /* GPIO Pin-Output Set registers */
+        DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return s->gpsr;    /* Return last written value.  */
+
+    case GPCR:        /* GPIO Pin-Output Clear registers */
+        DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return 31337;        /* Specified as unpredictable in the docs.  */
+
+    case GRER:        /* GPIO Rising-Edge Detect Enable registers */
+        return s->rising;
+
+    case GFER:        /* GPIO Falling-Edge Detect Enable registers */
+        return s->falling;
+
+    case GAFR:        /* GPIO Alternate Function registers */
+        return s->gafr;
+
+    case GPLR:        /* GPIO Pin-Level registers */
+        return (s->olevel & s->dir) |
+               (s->ilevel & ~s->dir);
+
+    case GEDR:        /* GPIO Edge Detect Status registers */
+        return s->status;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+
+    return 0;
+}
+
+static void strongarm_gpio_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    StrongARMGPIOInfo *s = opaque;
+
+    switch (offset) {
+    case GPDR:        /* GPIO Pin-Direction registers */
+        s->dir = value;
+        strongarm_gpio_handler_update(s);
+        break;
+
+    case GPSR:        /* GPIO Pin-Output Set registers */
+        s->olevel |= value;
+        strongarm_gpio_handler_update(s);
+        s->gpsr = value;
+        break;
+
+    case GPCR:        /* GPIO Pin-Output Clear registers */
+        s->olevel &= ~value;
+        strongarm_gpio_handler_update(s);
+        break;
+
+    case GRER:        /* GPIO Rising-Edge Detect Enable registers */
+        s->rising = value;
+        break;
+
+    case GFER:        /* GPIO Falling-Edge Detect Enable registers */
+        s->falling = value;
+        break;
+
+    case GAFR:        /* GPIO Alternate Function registers */
+        s->gafr = value;
+        break;
+
+    case GEDR:        /* GPIO Edge Detect Status registers */
+        s->status &= ~value;
+        strongarm_gpio_irq_update(s);
+        break;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_gpio_readfn[] = {
+    strongarm_gpio_read,
+    strongarm_gpio_read,
+    strongarm_gpio_read
+};
+
+static CPUWriteMemoryFunc * const strongarm_gpio_writefn[] = {
+    strongarm_gpio_write,
+    strongarm_gpio_write,
+    strongarm_gpio_write
+};
+
+static DeviceState *strongarm_gpio_init(target_phys_addr_t base,
+                DeviceState *pic)
+{
+    DeviceState *dev;
+    int i;
+
+    dev = qdev_create(NULL, "strongarm-gpio");
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    for (i = 0; i < 12; i++)
+        sysbus_connect_irq(sysbus_from_qdev(dev), i,
+                    qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i));
+
+    return dev;
+}
+
+static int strongarm_gpio_initfn(SysBusDevice *dev)
+{
+    int iomemtype;
+    StrongARMGPIOInfo *s;
+    int i;
+
+    s = FROM_SYSBUS(StrongARMGPIOInfo, dev);
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28);
+    qdev_init_gpio_out(&dev->qdev, s->handler, 28);
+
+    iomemtype = cpu_register_io_memory(strongarm_gpio_readfn,
+                    strongarm_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    for (i = 0; i < 11; i++) {
+        sysbus_init_irq(dev, &s->irqs[i]);
+    }
+    sysbus_init_irq(dev, &s->irqX);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_gpio_regs = {
+    .name = "strongarm-gpio",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
+        VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
+        VMSTATE_UINT32(dir, StrongARMGPIOInfo),
+        VMSTATE_UINT32(rising, StrongARMGPIOInfo),
+        VMSTATE_UINT32(falling, StrongARMGPIOInfo),
+        VMSTATE_UINT32(status, StrongARMGPIOInfo),
+        VMSTATE_UINT32(gafr, StrongARMGPIOInfo),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_gpio_info = {
+    .init       = strongarm_gpio_initfn,
+    .qdev.name  = "strongarm-gpio",
+    .qdev.desc  = "StrongARM GPIO controller",
+    .qdev.size  = sizeof(StrongARMGPIOInfo),
+};
+
+/* Peripheral Pin Controller */
+#define PPDR 0x00
+#define PPSR 0x04
+#define PPAR 0x08
+#define PSDR 0x0c
+#define PPFR 0x10
+
+typedef struct StrongARMPPCInfo StrongARMPPCInfo;
+struct StrongARMPPCInfo {
+    SysBusDevice busdev;
+    qemu_irq handler[28];
+
+    uint32_t ilevel;
+    uint32_t olevel;
+    uint32_t dir;
+    uint32_t ppar;
+    uint32_t psdr;
+    uint32_t ppfr;
+
+    uint32_t prev_level;
+};
+
+static void strongarm_ppc_set(void *opaque, int line, int level)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    if (level) {
+        s->ilevel |= 1 << line;
+    } else {
+        s->ilevel &= ~(1 << line);
+    }
+}
+
+static void strongarm_ppc_handler_update(StrongARMPPCInfo *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->olevel & s->dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+static uint32_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    switch (offset) {
+    case PPDR:        /* PPC Pin Direction registers */
+        return s->dir | ~0x3fffff;
+
+    case PPSR:        /* PPC Pin State registers */
+        return (s->olevel & s->dir) |
+               (s->ilevel & ~s->dir) |
+               ~0x3fffff;
+
+    case PPAR:
+        return s->ppar | ~0x41000;
+
+    case PSDR:
+        return s->psdr;
+
+    case PPFR:
+        return s->ppfr | ~0x7f001;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+
+    return 0;
+}
+
+static void strongarm_ppc_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    switch (offset) {
+    case PPDR:        /* PPC Pin Direction registers */
+        s->dir = value & 0x3fffff;
+        strongarm_ppc_handler_update(s);
+        break;
+
+    case PPSR:        /* PPC Pin State registers */
+        s->olevel = value & s->dir & 0x3fffff;
+        strongarm_ppc_handler_update(s);
+        break;
+
+    case PPAR:
+        s->ppar = value & 0x41000;
+        break;
+
+    case PSDR:
+        s->psdr = value & 0x3fffff;
+        break;
+
+    case PPFR:
+        s->ppfr = value & 0x7f001;
+        break;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_ppc_readfn[] = {
+    strongarm_ppc_read,
+    strongarm_ppc_read,
+    strongarm_ppc_read
+};
+
+static CPUWriteMemoryFunc * const strongarm_ppc_writefn[] = {
+    strongarm_ppc_write,
+    strongarm_ppc_write,
+    strongarm_ppc_write
+};
+
+static int strongarm_ppc_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    StrongARMPPCInfo *s;
+
+    s = FROM_SYSBUS(StrongARMPPCInfo, dev);
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22);
+    qdev_init_gpio_out(&dev->qdev, s->handler, 22);
+
+    iomemtype = cpu_register_io_memory(strongarm_ppc_readfn,
+                    strongarm_ppc_writefn, s, DEVICE_NATIVE_ENDIAN);
+
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_ppc_regs = {
+    .name = "strongarm-ppc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
+        VMSTATE_UINT32(olevel, StrongARMPPCInfo),
+        VMSTATE_UINT32(dir, StrongARMPPCInfo),
+        VMSTATE_UINT32(ppar, StrongARMPPCInfo),
+        VMSTATE_UINT32(psdr, StrongARMPPCInfo),
+        VMSTATE_UINT32(ppfr, StrongARMPPCInfo),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_ppc_info = {
+    .init       = strongarm_ppc_init,
+    .qdev.name  = "strongarm-ppc",
+    .qdev.desc  = "StrongARM PPC controller",
+    .qdev.size  = sizeof(StrongARMPPCInfo),
+};
+
+/* UART Ports */
+#define UTCR0 0x00
+#define UTCR1 0x04
+#define UTCR2 0x08
+#define UTCR3 0x0c
+#define UTDR  0x14
+#define UTSR0 0x1c
+#define UTSR1 0x20
+
+#define UTCR0_PE  (1 << 0) /* Parity enable */
+#define UTCR0_OES (1 << 1) /* Even parity */
+#define UTCR0_SBS (1 << 2) /* 2 stop bits */
+#define UTCR0_DSS (1 << 3) /* 8-bit data */
+
+#define UTCR3_RXE (1 << 0) /* Rx enable */
+#define UTCR3_TXE (1 << 1) /* Tx enable */
+#define UTCR3_BRK (1 << 2) /* Force Break */
+#define UTCR3_RIE (1 << 3) /* Rx int enable */
+#define UTCR3_TIE (1 << 4) /* Tx int enable */
+#define UTCR3_LBM (1 << 5) /* Loopback */
+
+#define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */
+#define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */
+#define UTSR0_RID (1 << 2) /* Receiver Idle */
+#define UTSR0_RBB (1 << 3) /* Receiver begin break */
+#define UTSR0_REB (1 << 4) /* Receiver end break */
+#define UTSR0_EIF (1 << 5) /* Error in FIFO */
+
+#define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */
+#define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */
+#define UTSR1_PRE (1 << 3) /* Parity error */
+#define UTSR1_FRE (1 << 4) /* Frame error */
+#define UTSR1_ROR (1 << 5) /* Receive Over Run */
+
+#define RX_FIFO_PRE (1 << 8)
+#define RX_FIFO_FRE (1 << 9)
+#define RX_FIFO_ROR (1 << 10)
+
+typedef struct {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint8_t utcr0;
+    uint16_t brd;
+    uint8_t utcr3;
+    uint8_t utsr0;
+    uint8_t utsr1;
+
+    uint8_t tx_fifo[8];
+    uint8_t tx_start;
+    uint8_t tx_len;
+    uint16_t rx_fifo[12]; /* value + error flags in high bits */
+    uint8_t rx_start;
+    uint8_t rx_len;
+
+    uint64_t char_transmit_time; /* time to transmit a char in ticks*/
+    bool wait_break_end;
+    QEMUTimer *rx_timeout_timer;
+    QEMUTimer *tx_timer;
+} StrongARMUARTState;
+
+static void strongarm_uart_update_status(StrongARMUARTState *s)
+{
+    uint16_t utsr1 = 0;
+
+    if (s->tx_len != 8) {
+        utsr1 |= UTSR1_TNF;
+    }
+
+    if (s->rx_len != 0) {
+        uint16_t ent = s->rx_fifo[s->rx_start];
+
+        utsr1 |= UTSR1_RNE;
+        if (ent & RX_FIFO_PRE) {
+            s->utsr1 |= UTSR1_PRE;
+        }
+        if (ent & RX_FIFO_FRE) {
+            s->utsr1 |= UTSR1_FRE;
+        }
+        if (ent & RX_FIFO_ROR) {
+            s->utsr1 |= UTSR1_ROR;
+        }
+    }
+
+    s->utsr1 = utsr1;
+}
+
+static void strongarm_uart_update_int_status(StrongARMUARTState *s)
+{
+    uint16_t utsr0 = s->utsr0 &
+            (UTSR0_REB | UTSR0_RBB | UTSR0_RID);
+    int i;
+
+    if ((s->utcr3 & UTCR3_TXE) &&
+                (s->utcr3 & UTCR3_TIE) &&
+                s->tx_len <= 4) {
+        utsr0 |= UTSR0_TFS;
+    }
+
+    if ((s->utcr3 & UTCR3_RXE) &&
+                (s->utcr3 & UTCR3_RIE) &&
+                s->rx_len > 4) {
+        utsr0 |= UTSR0_RFS;
+    }
+
+    for (i = 0; i < s->rx_len && i < 4; i++)
+        if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) {
+            utsr0 |= UTSR0_EIF;
+            break;
+        }
+
+    s->utsr0 = utsr0;
+    qemu_set_irq(s->irq, utsr0);
+}
+
+static void strongarm_uart_update_parameters(StrongARMUARTState *s)
+{
+    int speed, parity, data_bits, stop_bits, frame_size;
+    QEMUSerialSetParams ssp;
+
+    /* Start bit. */
+    frame_size = 1;
+    if (s->utcr0 & UTCR0_PE) {
+        /* Parity bit. */
+        frame_size++;
+        if (s->utcr0 & UTCR0_OES) {
+            parity = 'E';
+        } else {
+            parity = 'O';
+        }
+    } else {
+            parity = 'N';
+    }
+    if (s->utcr0 & UTCR0_SBS) {
+        stop_bits = 2;
+    } else {
+        stop_bits = 1;
+    }
+
+    data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7;
+    frame_size += data_bits + stop_bits;
+    speed = 3686400 / 16 / (s->brd + 1);
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
+    if (s->chr) {
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    }
+
+    DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
+            speed, parity, data_bits, stop_bits);
+}
+
+static void strongarm_uart_rx_to(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+
+    if (s->rx_len) {
+        s->utsr0 |= UTSR0_RID;
+        strongarm_uart_update_int_status(s);
+    }
+}
+
+static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c)
+{
+    if ((s->utcr3 & UTCR3_RXE) == 0) {
+        /* rx disabled */
+        return;
+    }
+
+    if (s->wait_break_end) {
+        s->utsr0 |= UTSR0_REB;
+        s->wait_break_end = false;
+    }
+
+    if (s->rx_len < 12) {
+        s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c;
+        s->rx_len++;
+    } else
+        s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR;
+}
+
+static int strongarm_uart_can_receive(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+
+    if (s->rx_len == 12) {
+        return 0;
+    }
+    /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */
+    if (s->rx_len < 8) {
+        return 8 - s->rx_len;
+    }
+    return 1;
+}
+
+static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    StrongARMUARTState *s = opaque;
+    int i;
+
+    for (i = 0; i < size; i++) {
+        strongarm_uart_rx_push(s, buf[i]);
+    }
+
+    /* call the timeout receive callback in 3 char transmit time */
+    qemu_mod_timer(s->rx_timeout_timer,
+                    qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3);
+
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static void strongarm_uart_event(void *opaque, int event)
+{
+    StrongARMUARTState *s = opaque;
+    if (event == CHR_EVENT_BREAK) {
+        s->utsr0 |= UTSR0_RBB;
+        strongarm_uart_rx_push(s, RX_FIFO_FRE);
+        s->wait_break_end = true;
+        strongarm_uart_update_status(s);
+        strongarm_uart_update_int_status(s);
+    }
+}
+
+static void strongarm_uart_tx(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+    uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
+
+    if (s->utcr3 & UTCR3_LBM) /* loopback */ {
+        strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
+    } else if (s->chr) {
+        qemu_chr_write(s->chr, &s->tx_fifo[s->tx_start], 1);
+    }
+
+    s->tx_start = (s->tx_start + 1) % 8;
+    s->tx_len--;
+    if (s->tx_len) {
+        qemu_mod_timer(s->tx_timer, new_xmit_ts + s->char_transmit_time);
+    }
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static uint32_t strongarm_uart_read(void *opaque, target_phys_addr_t addr)
+{
+    StrongARMUARTState *s = opaque;
+    uint16_t ret;
+
+    switch (addr) {
+    case UTCR0:
+        return s->utcr0;
+
+    case UTCR1:
+        return s->brd >> 8;
+
+    case UTCR2:
+        return s->brd & 0xff;
+
+    case UTCR3:
+        return s->utcr3;
+
+    case UTDR:
+        if (s->rx_len != 0) {
+            ret = s->rx_fifo[s->rx_start];
+            s->rx_start = (s->rx_start + 1) % 12;
+            s->rx_len--;
+            strongarm_uart_update_status(s);
+            strongarm_uart_update_int_status(s);
+            return ret;
+        }
+        return 0;
+
+    case UTSR0:
+        return s->utsr0;
+
+    case UTSR1:
+        return s->utsr1;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        return 0;
+    }
+}
+
+static void strongarm_uart_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    StrongARMUARTState *s = opaque;
+
+    switch (addr) {
+    case UTCR0:
+        s->utcr0 = value & 0x7f;
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR1:
+        s->brd = (s->brd & 0xff) | ((value & 0xf) << 8);
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR2:
+        s->brd = (s->brd & 0xf00) | (value & 0xff);
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR3:
+        s->utcr3 = value & 0x3f;
+        if ((s->utcr3 & UTCR3_RXE) == 0) {
+            s->rx_len = 0;
+        }
+        if ((s->utcr3 & UTCR3_TXE) == 0) {
+            s->tx_len = 0;
+        }
+        strongarm_uart_update_status(s);
+        strongarm_uart_update_int_status(s);
+        break;
+
+    case UTDR:
+        if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) {
+            s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value;
+            s->tx_len++;
+            strongarm_uart_update_status(s);
+            strongarm_uart_update_int_status(s);
+            if (s->tx_len == 1) {
+                strongarm_uart_tx(s);
+            }
+        }
+        break;
+
+    case UTSR0:
+        s->utsr0 = s->utsr0 & ~(value &
+                (UTSR0_REB | UTSR0_RBB | UTSR0_RID));
+        strongarm_uart_update_int_status(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_uart_readfn[] = {
+    strongarm_uart_read,
+    strongarm_uart_read,
+    strongarm_uart_read,
+};
+
+static CPUWriteMemoryFunc * const strongarm_uart_writefn[] = {
+    strongarm_uart_write,
+    strongarm_uart_write,
+    strongarm_uart_write,
+};
+
+static int strongarm_uart_init(SysBusDevice *dev)
+{
+    StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev);
+    int iomemtype;
+
+    iomemtype = cpu_register_io_memory(strongarm_uart_readfn,
+                    strongarm_uart_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x10000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+
+    s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s);
+    s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s);
+
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr,
+                        strongarm_uart_can_receive,
+                        strongarm_uart_receive,
+                        strongarm_uart_event,
+                        s);
+    }
+
+    return 0;
+}
+
+static void strongarm_uart_reset(DeviceState *dev)
+{
+    StrongARMUARTState *s = DO_UPCAST(StrongARMUARTState, busdev.qdev, dev);
+
+    s->utcr0 = UTCR0_DSS; /* 8 data, no parity */
+    s->brd = 23;    /* 9600 */
+    /* enable send & recv - this actually violates spec */
+    s->utcr3 = UTCR3_TXE | UTCR3_RXE;
+
+    s->rx_len = s->tx_len = 0;
+
+    strongarm_uart_update_parameters(s);
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static int strongarm_uart_post_load(void *opaque, int version_id)
+{
+    StrongARMUARTState *s = opaque;
+
+    strongarm_uart_update_parameters(s);
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+
+    /* tx and restart timer */
+    if (s->tx_len) {
+        strongarm_uart_tx(s);
+    }
+
+    /* restart rx timeout timer */
+    if (s->rx_len) {
+        qemu_mod_timer(s->rx_timeout_timer,
+                qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_uart_regs = {
+    .name = "strongarm-uart",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_uart_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(utcr0, StrongARMUARTState),
+        VMSTATE_UINT16(brd, StrongARMUARTState),
+        VMSTATE_UINT8(utcr3, StrongARMUARTState),
+        VMSTATE_UINT8(utsr0, StrongARMUARTState),
+        VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8),
+        VMSTATE_UINT8(tx_start, StrongARMUARTState),
+        VMSTATE_UINT8(tx_len, StrongARMUARTState),
+        VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12),
+        VMSTATE_UINT8(rx_start, StrongARMUARTState),
+        VMSTATE_UINT8(rx_len, StrongARMUARTState),
+        VMSTATE_BOOL(wait_break_end, StrongARMUARTState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_uart_info = {
+    .init       = strongarm_uart_init,
+    .qdev.name  = "strongarm-uart",
+    .qdev.desc  = "StrongARM UART controller",
+    .qdev.size  = sizeof(StrongARMUARTState),
+    .qdev.reset = strongarm_uart_reset,
+    .qdev.vmsd  = &vmstate_strongarm_uart_regs,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+/* Synchronous Serial Ports */
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq irq;
+    SSIBus *bus;
+
+    uint16_t sscr[2];
+    uint16_t sssr;
+
+    uint16_t rx_fifo[8];
+    uint8_t rx_level;
+    uint8_t rx_start;
+} StrongARMSSPState;
+
+#define SSCR0 0x60 /* SSP Control register 0 */
+#define SSCR1 0x64 /* SSP Control register 1 */
+#define SSDR  0x6c /* SSP Data register */
+#define SSSR  0x74 /* SSP Status register */
+
+/* Bitfields for above registers */
+#define SSCR0_SPI(x)    (((x) & 0x30) == 0x00)
+#define SSCR0_SSP(x)    (((x) & 0x30) == 0x10)
+#define SSCR0_UWIRE(x)  (((x) & 0x30) == 0x20)
+#define SSCR0_PSP(x)    (((x) & 0x30) == 0x30)
+#define SSCR0_SSE       (1 << 7)
+#define SSCR0_DSS(x)    (((x) & 0xf) + 1)
+#define SSCR1_RIE       (1 << 0)
+#define SSCR1_TIE       (1 << 1)
+#define SSCR1_LBM       (1 << 2)
+#define SSSR_TNF        (1 << 2)
+#define SSSR_RNE        (1 << 3)
+#define SSSR_TFS        (1 << 5)
+#define SSSR_RFS        (1 << 6)
+#define SSSR_ROR        (1 << 7)
+#define SSSR_RW         0x0080
+
+static void strongarm_ssp_int_update(StrongARMSSPState *s)
+{
+    int level = 0;
+
+    level |= (s->sssr & SSSR_ROR);
+    level |= (s->sssr & SSSR_RFS)  &&  (s->sscr[1] & SSCR1_RIE);
+    level |= (s->sssr & SSSR_TFS)  &&  (s->sscr[1] & SSCR1_TIE);
+    qemu_set_irq(s->irq, level);
+}
+
+static void strongarm_ssp_fifo_update(StrongARMSSPState *s)
+{
+    s->sssr &= ~SSSR_TFS;
+    s->sssr &= ~SSSR_TNF;
+    if (s->sscr[0] & SSCR0_SSE) {
+        if (s->rx_level >= 4) {
+            s->sssr |= SSSR_RFS;
+        } else {
+            s->sssr &= ~SSSR_RFS;
+        }
+        if (s->rx_level) {
+            s->sssr |= SSSR_RNE;
+        } else {
+            s->sssr &= ~SSSR_RNE;
+        }
+        /* TX FIFO is never filled, so it is always in underrun
+           condition if SSP is enabled */
+        s->sssr |= SSSR_TFS;
+        s->sssr |= SSSR_TNF;
+    }
+
+    strongarm_ssp_int_update(s);
+}
+
+static uint32_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr)
+{
+    StrongARMSSPState *s = opaque;
+    uint32_t retval;
+
+    switch (addr) {
+    case SSCR0:
+        return s->sscr[0];
+    case SSCR1:
+        return s->sscr[1];
+    case SSSR:
+        return s->sssr;
+    case SSDR:
+        if (~s->sscr[0] & SSCR0_SSE) {
+            return 0xffffffff;
+        }
+        if (s->rx_level < 1) {
+            printf("%s: SSP Rx Underrun\n", __func__);
+            return 0xffffffff;
+        }
+        s->rx_level--;
+        retval = s->rx_fifo[s->rx_start++];
+        s->rx_start &= 0x7;
+        strongarm_ssp_fifo_update(s);
+        return retval;
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    StrongARMSSPState *s = opaque;
+
+    switch (addr) {
+    case SSCR0:
+        s->sscr[0] = value & 0xffbf;
+        if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
+            printf("%s: Wrong data size: %i bits\n", __func__,
+                            SSCR0_DSS(value));
+        }
+        if (!(value & SSCR0_SSE)) {
+            s->sssr = 0;
+            s->rx_level = 0;
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    case SSCR1:
+        s->sscr[1] = value & 0x2f;
+        if (value & SSCR1_LBM) {
+            printf("%s: Attempt to use SSP LBM mode\n", __func__);
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    case SSSR:
+        s->sssr &= ~(value & SSSR_RW);
+        strongarm_ssp_int_update(s);
+        break;
+
+    case SSDR:
+        if (SSCR0_UWIRE(s->sscr[0])) {
+            value &= 0xff;
+        } else
+            /* Note how 32bits overflow does no harm here */
+            value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
+
+        /* Data goes from here to the Tx FIFO and is shifted out from
+         * there directly to the slave, no need to buffer it.
+         */
+        if (s->sscr[0] & SSCR0_SSE) {
+            uint32_t readval;
+            if (s->sscr[1] & SSCR1_LBM) {
+                readval = value;
+            } else {
+                readval = ssi_transfer(s->bus, value);
+            }
+
+            if (s->rx_level < 0x08) {
+                s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval;
+            } else {
+                s->sssr |= SSSR_ROR;
+            }
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const strongarm_ssp_readfn[] = {
+    strongarm_ssp_read,
+    strongarm_ssp_read,
+    strongarm_ssp_read,
+};
+
+static CPUWriteMemoryFunc * const strongarm_ssp_writefn[] = {
+    strongarm_ssp_write,
+    strongarm_ssp_write,
+    strongarm_ssp_write,
+};
+
+static int strongarm_ssp_post_load(void *opaque, int version_id)
+{
+    StrongARMSSPState *s = opaque;
+
+    strongarm_ssp_fifo_update(s);
+
+    return 0;
+}
+
+static int strongarm_ssp_init(SysBusDevice *dev)
+{
+    int iomemtype;
+    StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    iomemtype = cpu_register_io_memory(strongarm_ssp_readfn,
+                                       strongarm_ssp_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+
+    s->bus = ssi_create_bus(&dev->qdev, "ssi");
+    return 0;
+}
+
+static void strongarm_ssp_reset(DeviceState *dev)
+{
+    StrongARMSSPState *s = DO_UPCAST(StrongARMSSPState, busdev.qdev, dev);
+    s->sssr = 0x03; /* 3 bit data, SPI, disabled */
+    s->rx_start = 0;
+    s->rx_level = 0;
+}
+
+static const VMStateDescription vmstate_strongarm_ssp_regs = {
+    .name = "strongarm-ssp",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_ssp_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
+        VMSTATE_UINT16(sssr, StrongARMSSPState),
+        VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8),
+        VMSTATE_UINT8(rx_start, StrongARMSSPState),
+        VMSTATE_UINT8(rx_level, StrongARMSSPState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo strongarm_ssp_info = {
+    .init       = strongarm_ssp_init,
+    .qdev.name  = "strongarm-ssp",
+    .qdev.desc  = "StrongARM SSP controller",
+    .qdev.size  = sizeof(StrongARMSSPState),
+    .qdev.reset = strongarm_ssp_reset,
+    .qdev.vmsd  = &vmstate_strongarm_ssp_regs,
+};
+
+/* Main CPU functions */
+StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev)
+{
+    StrongARMState *s;
+    qemu_irq *pic;
+    int i;
+
+    s = qemu_mallocz(sizeof(StrongARMState));
+
+    if (!rev) {
+        rev = "sa1110-b5";
+    }
+
+    if (strncmp(rev, "sa1110", 6)) {
+        error_report("Machine requires a SA1110 processor.\n");
+        exit(1);
+    }
+
+    s->env = cpu_init(rev);
+
+    if (!s->env) {
+        error_report("Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    cpu_register_physical_memory(SA_SDCS0,
+                    sdram_size, qemu_ram_alloc(NULL, "strongarm.sdram",
+                                                sdram_size) | IO_MEM_RAM);
+
+    pic = arm_pic_init_cpu(s->env);
+    s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
+                    pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL);
+
+    sysbus_create_varargs("pxa25x-timer", 0x90000000,
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC0),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC1),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC2),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC3),
+                    NULL);
+
+    sysbus_create_simple("strongarm-rtc", 0x90010000,
+                    qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM));
+
+    s->gpio = strongarm_gpio_init(0x90040000, s->pic);
+
+    s->ppc = sysbus_create_varargs("strongarm-ppc", 0x90060000, NULL);
+
+    for (i = 0; sa_serial[i].io_base; i++) {
+        DeviceState *dev = qdev_create(NULL, "strongarm-uart");
+        qdev_prop_set_chr(dev, "chardev", serial_hds[i]);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(sysbus_from_qdev(dev), 0,
+                sa_serial[i].io_base);
+        sysbus_connect_irq(sysbus_from_qdev(dev), 0,
+                qdev_get_gpio_in(s->pic, sa_serial[i].irq));
+    }
+
+    s->ssp = sysbus_create_varargs("strongarm-ssp", 0x80070000,
+                qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL);
+    s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi");
+
+    return s;
+}
+
+static void strongarm_register_devices(void)
+{
+    sysbus_register_withprop(&strongarm_pic_info);
+    sysbus_register_withprop(&strongarm_rtc_sysbus_info);
+    sysbus_register_withprop(&strongarm_gpio_info);
+    sysbus_register_withprop(&strongarm_ppc_info);
+    sysbus_register_withprop(&strongarm_uart_info);
+    sysbus_register_withprop(&strongarm_ssp_info);
+}
+device_init(strongarm_register_devices)
diff --git a/hw/strongarm.h b/hw/strongarm.h
new file mode 100644 (file)
index 0000000..a81b110
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _STRONGARM_H
+#define _STRONGARM_H
+
+#define SA_CS0          0x00000000
+#define SA_CS1          0x08000000
+#define SA_CS2          0x10000000
+#define SA_CS3          0x18000000
+#define SA_PCMCIA_CS0   0x20000000
+#define SA_PCMCIA_CS1   0x30000000
+#define SA_CS4          0x40000000
+#define SA_CS5          0x48000000
+/* system registers here */
+#define SA_SDCS0        0xc0000000
+#define SA_SDCS1        0xc8000000
+#define SA_SDCS2        0xd0000000
+#define SA_SDCS3        0xd8000000
+
+enum {
+    SA_PIC_GPIO0_EDGE = 0,
+    SA_PIC_GPIO1_EDGE,
+    SA_PIC_GPIO2_EDGE,
+    SA_PIC_GPIO3_EDGE,
+    SA_PIC_GPIO4_EDGE,
+    SA_PIC_GPIO5_EDGE,
+    SA_PIC_GPIO6_EDGE,
+    SA_PIC_GPIO7_EDGE,
+    SA_PIC_GPIO8_EDGE,
+    SA_PIC_GPIO9_EDGE,
+    SA_PIC_GPIO10_EDGE,
+    SA_PIC_GPIOX_EDGE,
+    SA_PIC_LCD,
+    SA_PIC_UDC,
+    SA_PIC_RSVD1,
+    SA_PIC_UART1,
+    SA_PIC_UART2,
+    SA_PIC_UART3,
+    SA_PIC_MCP,
+    SA_PIC_SSP,
+    SA_PIC_DMA_CH0,
+    SA_PIC_DMA_CH1,
+    SA_PIC_DMA_CH2,
+    SA_PIC_DMA_CH3,
+    SA_PIC_DMA_CH4,
+    SA_PIC_DMA_CH5,
+    SA_PIC_OSTC0,
+    SA_PIC_OSTC1,
+    SA_PIC_OSTC2,
+    SA_PIC_OSTC3,
+    SA_PIC_RTC_HZ,
+    SA_PIC_RTC_ALARM,
+};
+
+typedef struct {
+    CPUState *env;
+    DeviceState *pic;
+    DeviceState *gpio;
+    DeviceState *ppc;
+    DeviceState *ssp;
+    SSIBus *ssp_bus;
+} StrongARMState;
+
+StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev);
+
+#endif
index dbb5a15066572d7feb6adc18fcc8e5e8c1dec529..5eb38cf27dc5bbf806347d5418f3a9dc397d7b27 100644 (file)
@@ -793,14 +793,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
     for(i = 0; i < nb_nics; i++)
         pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
 
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
-    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
-        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS,
-                          i % MAX_IDE_DEVS);
-    }
+    ide_drive_get(hd, MAX_IDE_BUS);
 
     pci_cmd646_ide_init(pci_bus, hd, 1);
 
index 758c69a9cdb1ba5b4e59dd072d4714d82649dd8f..bc200e48aabdd09a56fcdec3e616761cfd88ca21 100644 (file)
@@ -25,7 +25,6 @@
 #include "sysbus.h"
 #include "boards.h"
 #include "arm-misc.h"
-#include "sysemu.h"
 #include "net.h"
 
 static struct arm_boot_info syborg_binfo;
index d295e99ebdae7710794e68eb30ccffc44b56ddc3..706a03966f33e7946074ecab6d1fcdfbab33067f 100644 (file)
@@ -51,11 +51,11 @@ enum {
 
 typedef struct {
     SysBusDevice busdev;
-    int int_enabled;
+    uint32_t int_enabled;
     int extension_bit;
     uint32_t fifo_size;
     uint32_t *key_fifo;
-    int read_pos, read_count;
+    uint32_t read_pos, read_count;
     qemu_irq irq;
 } SyborgKeyboardState;
 
@@ -165,43 +165,21 @@ static void syborg_keyboard_event(void *opaque, int keycode)
     syborg_keyboard_update(s);
 }
 
-static void syborg_keyboard_save(QEMUFile *f, void *opaque)
-{
-    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->fifo_size);
-    qemu_put_be32(f, s->int_enabled);
-    qemu_put_be32(f, s->extension_bit);
-    qemu_put_be32(f, s->read_pos);
-    qemu_put_be32(f, s->read_count);
-    for (i = 0; i < s->fifo_size; i++) {
-        qemu_put_be32(f, s->key_fifo[i]);
-    }
-}
-
-static int syborg_keyboard_load(QEMUFile *f, void *opaque, int version_id)
-{
-    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
-    uint32_t val;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    val = qemu_get_be32(f);
-    if (val != s->fifo_size)
-        return -EINVAL;
-
-    s->int_enabled = qemu_get_be32(f);
-    s->extension_bit = qemu_get_be32(f);
-    s->read_pos = qemu_get_be32(f);
-    s->read_count = qemu_get_be32(f);
-    for (i = 0; i < s->fifo_size; i++) {
-        s->key_fifo[i] = qemu_get_be32(f);
+static const VMStateDescription vmstate_syborg_keyboard = {
+    .name = "syborg_keyboard",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_EQUAL(fifo_size, SyborgKeyboardState),
+        VMSTATE_UINT32(int_enabled, SyborgKeyboardState),
+        VMSTATE_UINT32(read_pos, SyborgKeyboardState),
+        VMSTATE_UINT32(read_count, SyborgKeyboardState),
+        VMSTATE_VARRAY_UINT32(key_fifo, SyborgKeyboardState, fifo_size, 1,
+                              vmstate_info_uint32, uint32),
+        VMSTATE_END_OF_LIST()
     }
-    return 0;
-}
+};
 
 static int syborg_keyboard_init(SysBusDevice *dev)
 {
@@ -221,8 +199,7 @@ static int syborg_keyboard_init(SysBusDevice *dev)
 
     qemu_add_kbd_event_handler(syborg_keyboard_event, s);
 
-    register_savevm(&dev->qdev, "syborg_keyboard", -1, 1,
-                    syborg_keyboard_save, syborg_keyboard_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_syborg_keyboard, s);
     return 0;
 }
 
index a88688846741678399cd8e09c9ad0aa4d5f0da0c..2f99707040585356609597a890a9725fa71d2bc6 100644 (file)
@@ -152,52 +152,36 @@ static void syborg_pointer_event(void *opaque, int dx, int dy, int dz,
     syborg_pointer_update(s);
 }
 
-static void syborg_pointer_save(QEMUFile *f, void *opaque)
-{
-    SyborgPointerState *s = (SyborgPointerState *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->fifo_size);
-    qemu_put_be32(f, s->absolute);
-    qemu_put_be32(f, s->int_enabled);
-    qemu_put_be32(f, s->read_pos);
-    qemu_put_be32(f, s->read_count);
-    for (i = 0; i < s->fifo_size; i++) {
-        qemu_put_be32(f, s->event_fifo[i].x);
-        qemu_put_be32(f, s->event_fifo[i].y);
-        qemu_put_be32(f, s->event_fifo[i].z);
-        qemu_put_be32(f, s->event_fifo[i].pointer_buttons);
+static const VMStateDescription vmstate_event_data = {
+    .name = "dbma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(x, event_data),
+        VMSTATE_INT32(y, event_data),
+        VMSTATE_INT32(z, event_data),
+        VMSTATE_INT32(pointer_buttons, event_data),
+        VMSTATE_END_OF_LIST()
     }
-}
+};
 
-static int syborg_pointer_load(QEMUFile *f, void *opaque, int version_id)
-{
-    SyborgPointerState *s = (SyborgPointerState *)opaque;
-    uint32_t val;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    val = qemu_get_be32(f);
-    if (val != s->fifo_size)
-        return -EINVAL;
-
-    val = qemu_get_be32(f);
-    if (val != s->absolute)
-        return -EINVAL;
-
-    s->int_enabled = qemu_get_be32(f);
-    s->read_pos = qemu_get_be32(f);
-    s->read_count = qemu_get_be32(f);
-    for (i = 0; i < s->fifo_size; i++) {
-        s->event_fifo[i].x = qemu_get_be32(f);
-        s->event_fifo[i].y = qemu_get_be32(f);
-        s->event_fifo[i].z = qemu_get_be32(f);
-        s->event_fifo[i].pointer_buttons = qemu_get_be32(f);
+static const VMStateDescription vmstate_syborg_pointer = {
+    .name = "syborg_pointer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_EQUAL(fifo_size, SyborgPointerState),
+        VMSTATE_UINT32_EQUAL(absolute, SyborgPointerState),
+        VMSTATE_INT32(int_enabled, SyborgPointerState),
+        VMSTATE_INT32(read_pos, SyborgPointerState),
+        VMSTATE_INT32(read_count, SyborgPointerState),
+        VMSTATE_STRUCT_VARRAY_UINT32(event_fifo, SyborgPointerState, fifo_size,
+                                     1, vmstate_event_data, event_data),
+        VMSTATE_END_OF_LIST()
     }
-    return 0;
-}
+};
 
 static int syborg_pointer_init(SysBusDevice *dev)
 {
@@ -219,8 +203,7 @@ static int syborg_pointer_init(SysBusDevice *dev)
     qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute,
                                  "Syborg Pointer");
 
-    register_savevm(&dev->qdev, "syborg_pointer", -1, 1,
-                    syborg_pointer_save, syborg_pointer_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_syborg_pointer, s);
     return 0;
 }
 
index 16d8f9edb89383f548b93b08a696595a1a342c11..69f6ccf29cc395db23bff7d267a0c65a25381dd2 100644 (file)
@@ -102,26 +102,17 @@ static CPUWriteMemoryFunc * const syborg_rtc_writefn[] = {
     syborg_rtc_write
 };
 
-static void syborg_rtc_save(QEMUFile *f, void *opaque)
-{
-    SyborgRTCState *s = opaque;
-
-    qemu_put_be64(f, s->offset);
-    qemu_put_be64(f, s->data);
-}
-
-static int syborg_rtc_load(QEMUFile *f, void *opaque, int version_id)
-{
-    SyborgRTCState *s = opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->offset = qemu_get_be64(f);
-    s->data = qemu_get_be64(f);
-
-    return 0;
-}
+static const VMStateDescription vmstate_syborg_rtc = {
+    .name = "syborg_keyboard",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT64(offset, SyborgRTCState),
+        VMSTATE_INT64(data, SyborgRTCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int syborg_rtc_init(SysBusDevice *dev)
 {
@@ -137,8 +128,7 @@ static int syborg_rtc_init(SysBusDevice *dev)
     qemu_get_timedate(&tm, 0);
     s->offset = (uint64_t)mktime(&tm) * 1000000000;
 
-    register_savevm(&dev->qdev, "syborg_rtc", -1, 1,
-                    syborg_rtc_save, syborg_rtc_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_syborg_rtc, s);
     return 0;
 }
 
index 34ce076d45c22e21b42e6fd3d682977608d2740e..df2950fe885680cfb771cdfad11b906886717a40 100644 (file)
@@ -273,47 +273,24 @@ static CPUWriteMemoryFunc * const syborg_serial_writefn[] = {
      syborg_serial_write
 };
 
-static void syborg_serial_save(QEMUFile *f, void *opaque)
-{
-    SyborgSerialState *s = opaque;
-    int i;
-
-    qemu_put_be32(f, s->fifo_size);
-    qemu_put_be32(f, s->int_enable);
-    qemu_put_be32(f, s->read_pos);
-    qemu_put_be32(f, s->read_count);
-    qemu_put_be32(f, s->dma_tx_ptr);
-    qemu_put_be32(f, s->dma_rx_ptr);
-    qemu_put_be32(f, s->dma_rx_size);
-    for (i = 0; i < s->fifo_size; i++) {
-        qemu_put_be32(f, s->read_fifo[i]);
-    }
-}
-
-static int syborg_serial_load(QEMUFile *f, void *opaque, int version_id)
-{
-    SyborgSerialState *s = opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    i = qemu_get_be32(f);
-    if (s->fifo_size != i)
-        return -EINVAL;
-
-    s->int_enable = qemu_get_be32(f);
-    s->read_pos = qemu_get_be32(f);
-    s->read_count = qemu_get_be32(f);
-    s->dma_tx_ptr = qemu_get_be32(f);
-    s->dma_rx_ptr = qemu_get_be32(f);
-    s->dma_rx_size = qemu_get_be32(f);
-    for (i = 0; i < s->fifo_size; i++) {
-        s->read_fifo[i] = qemu_get_be32(f);
+static const VMStateDescription vmstate_syborg_serial = {
+    .name = "syborg_serial",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_EQUAL(fifo_size, SyborgSerialState),
+        VMSTATE_UINT32(int_enable, SyborgSerialState),
+        VMSTATE_INT32(read_pos, SyborgSerialState),
+        VMSTATE_INT32(read_count, SyborgSerialState),
+        VMSTATE_UINT32(dma_tx_ptr, SyborgSerialState),
+        VMSTATE_UINT32(dma_rx_ptr, SyborgSerialState),
+        VMSTATE_UINT32(dma_rx_size, SyborgSerialState),
+        VMSTATE_VARRAY_UINT32(read_fifo, SyborgSerialState, fifo_size, 1,
+                              vmstate_info_uint32, uint32),
+        VMSTATE_END_OF_LIST()
     }
-
-    return 0;
-}
+};
 
 static int syborg_serial_init(SysBusDevice *dev)
 {
@@ -336,8 +313,6 @@ static int syborg_serial_init(SysBusDevice *dev)
     }
     s->read_fifo = qemu_mallocz(s->fifo_size * sizeof(s->read_fifo[0]));
 
-    register_savevm(&dev->qdev, "syborg_serial", -1, 1,
-                    syborg_serial_save, syborg_serial_load, s);
     return 0;
 }
 
@@ -345,6 +320,7 @@ static SysBusDeviceInfo syborg_serial_info = {
     .init = syborg_serial_init,
     .qdev.name  = "syborg,serial",
     .qdev.size  = sizeof(SyborgSerialState),
+    .qdev.vmsd  = &vmstate_syborg_serial,
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT32("fifo-size", SyborgSerialState, fifo_size, 16),
         DEFINE_PROP_END_OF_LIST(),
index cedcd8ed47a82c436c21abb8180292d1681fc7b7..50c813e9692992e1c0eaef7cac70c8e26b68fd60 100644 (file)
@@ -174,34 +174,21 @@ static CPUWriteMemoryFunc * const syborg_timer_writefn[] = {
     syborg_timer_write
 };
 
-static void syborg_timer_save(QEMUFile *f, void *opaque)
-{
-    SyborgTimerState *s = opaque;
-
-    qemu_put_be32(f, s->running);
-    qemu_put_be32(f, s->oneshot);
-    qemu_put_be32(f, s->limit);
-    qemu_put_be32(f, s->int_level);
-    qemu_put_be32(f, s->int_enabled);
-    qemu_put_ptimer(f, s->timer);
-}
-
-static int syborg_timer_load(QEMUFile *f, void *opaque, int version_id)
-{
-    SyborgTimerState *s = opaque;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->running = qemu_get_be32(f);
-    s->oneshot = qemu_get_be32(f);
-    s->limit = qemu_get_be32(f);
-    s->int_level = qemu_get_be32(f);
-    s->int_enabled = qemu_get_be32(f);
-    qemu_get_ptimer(f, s->timer);
-
-    return 0;
-}
+static const VMStateDescription vmstate_syborg_timer = {
+    .name = "syborg_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(running, SyborgTimerState),
+        VMSTATE_INT32(oneshot, SyborgTimerState),
+        VMSTATE_UINT32(limit, SyborgTimerState),
+        VMSTATE_UINT32(int_level, SyborgTimerState),
+        VMSTATE_UINT32(int_enabled, SyborgTimerState),
+        VMSTATE_PTIMER(timer, SyborgTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static int syborg_timer_init(SysBusDevice *dev)
 {
@@ -222,8 +209,7 @@ static int syborg_timer_init(SysBusDevice *dev)
     bh = qemu_bh_new(syborg_timer_tick, s);
     s->timer = ptimer_init(bh);
     ptimer_set_freq(s->timer, s->freq);
-    register_savevm(&dev->qdev, "syborg_timer", -1, 1,
-                    syborg_timer_save, syborg_timer_load, s);
+    vmstate_register(&dev->qdev, -1, &vmstate_syborg_timer, s);
     return 0;
 }
 
index ee08c49105f8ed6c33e02c7612f5eda501895236..2f3e6da4e236151fc24fd1c139ddd76ba4832dd2 100644 (file)
@@ -26,7 +26,6 @@
 #include "sysbus.h"
 #include "virtio.h"
 #include "virtio-net.h"
-#include "sysemu.h"
 
 //#define DEBUG_SYBORG_VIRTIO
 
index acad72abe450c2725722564b80c352624dfab6ec..2e22be7b25ba227f7c2bce122f950360c8179f2c 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include "sysbus.h"
-#include "sysemu.h"
 #include "monitor.h"
 
 static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
index 672a01c467be53199f1850828e73de61888da007..61b99dd4daa9516e080219041b13725e1e7c5f35 100644 (file)
@@ -1,6 +1,5 @@
 #include "hw.h"
 #include "sh.h"
-#include "sysemu.h"
 #include "loader.h"
 
 #define CE1  0x0100
index b8b6c4f3908c53edabeb9fc0374b9b03a9f50fc4..a7967a286ea5e2835370fda15d1672388fab3386 100644 (file)
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -11,7 +11,6 @@
 #include "hw.h"
 #include "pxa.h"
 #include "arm-misc.h"
-#include "sysemu.h"
 #include "devices.h"
 #include "sharpsl.h"
 #include "pcmcia.h"
index 8e74acc059ad29f5872dd458589efd7bb89b48d9..a75448f06ab44f153546f4216590789a6bdb9329 100644 (file)
@@ -22,7 +22,6 @@
 #include "hw.h"
 #include "qemu-timer.h"
 #include "i2c.h"
-#include "sysemu.h"
 #include "console.h"
 
 #define VERBOSE 1
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
new file mode 100644 (file)
index 0000000..079b4a2
--- /dev/null
@@ -0,0 +1,1419 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * CCID Device emulation
+ *
+ * Written by Alon Levy, with contributions from Robert Relyea.
+ *
+ * Based on usb-serial.c, see it's copyright and attributions below.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ * ------- (original copyright & attribution for usb-serial.c below) --------
+ * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
+ * Written by Paul Brook, reused for FTDI by Samuel Thibault,
+ */
+
+/*
+ * References:
+ *
+ * CCID Specification Revision 1.1 April 22nd 2005
+ *  "Universal Serial Bus, Device Class: Smart Card"
+ *  Specification for Integrated Circuit(s) Cards Interface Devices
+ *
+ * Endianness note: from the spec (1.3)
+ *  "Fields that are larger than a byte are stored in little endian"
+ *
+ * KNOWN BUGS
+ * 1. remove/insert can sometimes result in removed state instead of inserted.
+ * This is a result of the following:
+ *  symptom: dmesg shows ERMOTEIO (-121), pcscd shows -99. This can happen
+ *  when a short packet is sent, as seen in uhci-usb.c, resulting from a urb
+ *  from the guest requesting SPD and us returning a smaller packet.
+ *  Not sure which messages trigger this.
+ */
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "usb.h"
+#include "monitor.h"
+
+#include "hw/ccid.h"
+
+#define DPRINTF(s, lvl, fmt, ...) \
+do { \
+    if (lvl <= s->debug) { \
+        printf("usb-ccid: " fmt , ## __VA_ARGS__); \
+    } \
+} while (0)
+
+#define D_WARN 1
+#define D_INFO 2
+#define D_MORE_INFO 3
+#define D_VERBOSE 4
+
+#define CCID_DEV_NAME "usb-ccid"
+
+/*
+ * The two options for variable sized buffers:
+ * make them constant size, for large enough constant,
+ * or handle the migration complexity - VMState doesn't handle this case.
+ * sizes are expected never to be exceeded, unless guest misbehaves.
+ */
+#define BULK_OUT_DATA_SIZE 65536
+#define PENDING_ANSWERS_NUM 128
+
+#define BULK_IN_BUF_SIZE 384
+#define BULK_IN_PENDING_NUM 8
+
+#define InterfaceOutClass \
+    ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8)
+
+#define InterfaceInClass  \
+    ((USB_DIR_IN  | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8)
+
+#define CCID_MAX_PACKET_SIZE                64
+
+#define CCID_CONTROL_ABORT                  0x1
+#define CCID_CONTROL_GET_CLOCK_FREQUENCIES  0x2
+#define CCID_CONTROL_GET_DATA_RATES         0x3
+
+#define CCID_PRODUCT_DESCRIPTION        "QEMU USB CCID"
+#define CCID_VENDOR_DESCRIPTION         "QEMU " QEMU_VERSION
+#define CCID_INTERFACE_NAME             "CCID Interface"
+#define CCID_SERIAL_NUMBER_STRING       "1"
+/*
+ * Using Gemplus Vendor and Product id
+ * Effect on various drivers:
+ *  usbccid.sys (winxp, others untested) is a class driver so it doesn't care.
+ *  linux has a number of class drivers, but openct filters based on
+ *   vendor/product (/etc/openct.conf under fedora), hence Gemplus.
+ */
+#define CCID_VENDOR_ID                  0x08e6
+#define CCID_PRODUCT_ID                 0x4433
+#define CCID_DEVICE_VERSION             0x0000
+
+/*
+ * BULK_OUT messages from PC to Reader
+ * Defined in CCID Rev 1.1 6.1 (page 26)
+ */
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn              0x62
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff             0x63
+#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus           0x65
+#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock                0x6f
+#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters           0x6c
+#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters         0x6d
+#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters           0x61
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape                  0x6b
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock                0x6e
+#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU                  0x6a
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure                  0x69
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical              0x71
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort                   0x72
+#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
+
+/*
+ * BULK_IN messages from Reader to PC
+ * Defined in CCID Rev 1.1 6.2 (page 48)
+ */
+#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock               0x80
+#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus              0x81
+#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters              0x82
+#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape                  0x83
+#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84
+
+/*
+ * INTERRUPT_IN messages from Reader to PC
+ * Defined in CCID Rev 1.1 6.3 (page 56)
+ */
+#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange        0x50
+#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError           0x51
+
+/*
+ * Endpoints for CCID - addresses are up to us to decide.
+ * To support slot insertion and removal we must have an interrupt in ep
+ * in addition we need a bulk in and bulk out ep
+ * 5.2, page 20
+ */
+#define CCID_INT_IN_EP       1
+#define CCID_BULK_IN_EP      2
+#define CCID_BULK_OUT_EP     3
+
+/* bmSlotICCState masks */
+#define SLOT_0_STATE_MASK    1
+#define SLOT_0_CHANGED_MASK  2
+
+/* Status codes that go in bStatus (see 6.2.6) */
+enum {
+    ICC_STATUS_PRESENT_ACTIVE = 0,
+    ICC_STATUS_PRESENT_INACTIVE,
+    ICC_STATUS_NOT_PRESENT
+};
+
+enum {
+    COMMAND_STATUS_NO_ERROR = 0,
+    COMMAND_STATUS_FAILED,
+    COMMAND_STATUS_TIME_EXTENSION_REQUIRED
+};
+
+/* Error codes that go in bError (see 6.2.6) */
+enum {
+    ERROR_CMD_NOT_SUPPORTED = 0,
+    ERROR_CMD_ABORTED       = -1,
+    ERROR_ICC_MUTE          = -2,
+    ERROR_XFR_PARITY_ERROR  = -3,
+    ERROR_XFR_OVERRUN       = -4,
+    ERROR_HW_ERROR          = -5,
+};
+
+/* 6.2.6 RDR_to_PC_SlotStatus definitions */
+enum {
+    CLOCK_STATUS_RUNNING = 0,
+    /*
+     * 0 - Clock Running, 1 - Clock stopped in State L, 2 - H,
+     * 3 - unknown state. rest are RFU
+     */
+};
+
+typedef struct __attribute__ ((__packed__)) CCID_Header {
+    uint8_t     bMessageType;
+    uint32_t    dwLength;
+    uint8_t     bSlot;
+    uint8_t     bSeq;
+} CCID_Header;
+
+typedef struct __attribute__ ((__packed__)) CCID_BULK_IN {
+    CCID_Header hdr;
+    uint8_t     bStatus;        /* Only used in BULK_IN */
+    uint8_t     bError;         /* Only used in BULK_IN */
+} CCID_BULK_IN;
+
+typedef struct __attribute__ ((__packed__)) CCID_SlotStatus {
+    CCID_BULK_IN b;
+    uint8_t     bClockStatus;
+} CCID_SlotStatus;
+
+typedef struct __attribute__ ((__packed__)) CCID_Parameter {
+    CCID_BULK_IN b;
+    uint8_t     bProtocolNum;
+    uint8_t     abProtocolDataStructure[0];
+} CCID_Parameter;
+
+typedef struct __attribute__ ((__packed__)) CCID_DataBlock {
+    CCID_BULK_IN b;
+    uint8_t      bChainParameter;
+    uint8_t      abData[0];
+} CCID_DataBlock;
+
+/* 6.1.4 PC_to_RDR_XfrBlock */
+typedef struct __attribute__ ((__packed__)) CCID_XferBlock {
+    CCID_Header  hdr;
+    uint8_t      bBWI; /* Block Waiting Timeout */
+    uint16_t     wLevelParameter; /* XXX currently unused */
+    uint8_t      abData[0];
+} CCID_XferBlock;
+
+typedef struct __attribute__ ((__packed__)) CCID_IccPowerOn {
+    CCID_Header hdr;
+    uint8_t     bPowerSelect;
+    uint16_t    abRFU;
+} CCID_IccPowerOn;
+
+typedef struct __attribute__ ((__packed__)) CCID_IccPowerOff {
+    CCID_Header hdr;
+    uint16_t    abRFU;
+} CCID_IccPowerOff;
+
+typedef struct __attribute__ ((__packed__)) CCID_SetParameters {
+    CCID_Header hdr;
+    uint8_t     bProtocolNum;
+    uint16_t   abRFU;
+    uint8_t    abProtocolDataStructure[0];
+} CCID_SetParameters;
+
+typedef struct CCID_Notify_Slot_Change {
+    uint8_t     bMessageType; /* CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange */
+    uint8_t     bmSlotICCState;
+} CCID_Notify_Slot_Change;
+
+/* used for DataBlock response to XferBlock */
+typedef struct Answer {
+    uint8_t slot;
+    uint8_t seq;
+} Answer;
+
+/* pending BULK_IN messages */
+typedef struct BulkIn {
+    uint8_t  data[BULK_IN_BUF_SIZE];
+    uint32_t len;
+    uint32_t pos;
+} BulkIn;
+
+enum {
+    MIGRATION_NONE,
+    MIGRATION_MIGRATED,
+};
+
+typedef struct CCIDBus CCIDBus;
+typedef struct USBCCIDState USBCCIDState;
+
+#define MAX_PROTOCOL_SIZE   7
+
+/*
+ * powered - defaults to true, changed by PowerOn/PowerOff messages
+ */
+struct USBCCIDState {
+    USBDevice dev;
+    CCIDBus *bus;
+    CCIDCardState *card;
+    CCIDCardInfo *cardinfo; /* caching the info pointer */
+    BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
+    uint32_t bulk_in_pending_start;
+    uint32_t bulk_in_pending_end; /* first free */
+    uint32_t bulk_in_pending_num;
+    BulkIn *current_bulk_in;
+    uint8_t  bulk_out_data[BULK_OUT_DATA_SIZE];
+    uint32_t bulk_out_pos;
+    uint64_t last_answer_error;
+    Answer pending_answers[PENDING_ANSWERS_NUM];
+    uint32_t pending_answers_start;
+    uint32_t pending_answers_end;
+    uint32_t pending_answers_num;
+    uint8_t  bError;
+    uint8_t  bmCommandStatus;
+    uint8_t  bProtocolNum;
+    uint8_t  abProtocolDataStructure[MAX_PROTOCOL_SIZE];
+    uint32_t ulProtocolDataStructureSize;
+    uint32_t state_vmstate;
+    uint32_t migration_target_ip;
+    uint16_t migration_target_port;
+    uint8_t  migration_state;
+    uint8_t  bmSlotICCState;
+    uint8_t  powered;
+    uint8_t  notify_slot_change;
+    uint8_t  debug;
+};
+
+/*
+ * CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
+ * "USB Device Framework", section 9.6.1, in the Universal Serial Bus
+ * Specification.
+ *
+ * This device implemented based on the spec and with an Athena Smart Card
+ * Reader as reference:
+ *   0dc3:1004 Athena Smartcard Solutions, Inc.
+ */
+
+static const uint8_t qemu_ccid_dev_descriptor[] = {
+        0x12,       /*  u8 bLength; */
+        USB_DT_DEVICE, /*  u8 bDescriptorType; Device */
+        0x10, 0x01, /*  u16 bcdUSB; v1.1 */
+
+        0x00,       /*  u8  bDeviceClass; */
+        0x00,       /*  u8  bDeviceSubClass; */
+        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
+        0x40,       /*  u8  bMaxPacketSize0; 8 Bytes (valid: 8,16,32,64) */
+
+        /* Vendor and product id are arbitrary.  */
+                    /*  u16 idVendor  */
+        CCID_VENDOR_ID & 0xff, CCID_VENDOR_ID >> 8,
+                    /*  u16 idProduct */
+        CCID_PRODUCT_ID & 0xff, CCID_PRODUCT_ID >> 8,
+                    /*  u16 bcdDevice */
+        CCID_DEVICE_VERSION & 0xff, CCID_DEVICE_VERSION >> 8,
+        0x01,       /*  u8  iManufacturer; */
+        0x02,       /*  u8  iProduct; */
+        0x03,       /*  u8  iSerialNumber; */
+        0x01,       /*  u8  bNumConfigurations; */
+};
+
+static const uint8_t qemu_ccid_config_descriptor[] = {
+
+        /* one configuration */
+        0x09,       /* u8  bLength; */
+        USB_DT_CONFIG, /* u8  bDescriptorType; Configuration */
+        0x5d, 0x00, /* u16 wTotalLength; 9+9+54+7+7+7 */
+        0x01,       /* u8  bNumInterfaces; (1) */
+        0x01,       /* u8  bConfigurationValue; */
+        0x00,       /* u8  iConfiguration; */
+        0xe0,       /* u8  bmAttributes;
+                                 Bit 7: must be set,
+                                     6: Self-powered,
+                                     5: Remote wakeup,
+                                     4..0: resvd */
+        100/2,      /* u8  MaxPower; 50 == 100mA */
+
+        /* one interface */
+        0x09,       /* u8  if_bLength; */
+        USB_DT_INTERFACE, /* u8  if_bDescriptorType; Interface */
+        0x00,       /* u8  if_bInterfaceNumber; */
+        0x00,       /* u8  if_bAlternateSetting; */
+        0x03,       /* u8  if_bNumEndpoints; */
+        0x0b,       /* u8  if_bInterfaceClass; Smart Card Device Class */
+        0x00,       /* u8  if_bInterfaceSubClass; Subclass code */
+        0x00,       /* u8  if_bInterfaceProtocol; Protocol code */
+        0x04,       /* u8  if_iInterface; Index of string descriptor */
+
+        /* Smart Card Device Class Descriptor */
+        0x36,       /* u8  bLength; */
+        0x21,       /* u8  bDescriptorType; Functional */
+        0x10, 0x01, /* u16 bcdCCID; CCID Specification Release Number. */
+        0x00,       /*
+                     * u8  bMaxSlotIndex; The index of the highest available
+                     * slot on this device. All slots are consecutive starting
+                     * at 00h.
+                     */
+        0x07,       /* u8  bVoltageSupport; 01h - 5.0v, 02h - 3.0, 03 - 1.8 */
+
+        0x03, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/
+        0x00, 0x00, /* PPPP: 0001h = Protocol T=0, 0002h = Protocol T=1 */
+                    /* u32 dwDefaultClock; in kHZ (0x0fa0 is 4 MHz) */
+        0xa0, 0x0f, 0x00, 0x00,
+                    /* u32 dwMaximumClock; */
+        0x00, 0x00, 0x01, 0x00,
+        0x00,       /* u8 bNumClockSupported;                 *
+                     *    0 means just the default and max.   */
+                    /* u32 dwDataRate ;bps. 9600 == 00002580h */
+        0x80, 0x25, 0x00, 0x00,
+                    /* u32 dwMaxDataRate ; 11520 bps == 0001C200h */
+        0x00, 0xC2, 0x01, 0x00,
+        0x00,       /* u8  bNumDataRatesSupported; 00 means all rates between
+                     *     default and max */
+                    /* u32 dwMaxIFSD;                                  *
+                     *     maximum IFSD supported by CCID for protocol *
+                     *     T=1 (Maximum seen from various cards)       */
+        0xfe, 0x00, 0x00, 0x00,
+                    /* u32 dwSyncProtocols; 1 - 2-wire, 2 - 3-wire, 4 - I2C */
+        0x00, 0x00, 0x00, 0x00,
+                    /* u32 dwMechanical;  0 - no special characteristics. */
+        0x00, 0x00, 0x00, 0x00,
+                    /*
+                     * u32 dwFeatures;
+                     * 0 - No special characteristics
+                     * + 2 Automatic parameter configuration based on ATR data
+                     * + 4 Automatic activation of ICC on inserting
+                     * + 8 Automatic ICC voltage selection
+                     * + 10 Automatic ICC clock frequency change
+                     * + 20 Automatic baud rate change
+                     * + 40 Automatic parameters negotiation made by the CCID
+                     * + 80 automatic PPS made by the CCID
+                     * 100 CCID can set ICC in clock stop mode
+                     * 200 NAD value other then 00 accepted (T=1 protocol)
+                     * + 400 Automatic IFSD exchange as first exchange (T=1)
+                     * One of the following only:
+                     * + 10000 TPDU level exchanges with CCID
+                     * 20000 Short APDU level exchange with CCID
+                     * 40000 Short and Extended APDU level exchange with CCID
+                     *
+                     * + 100000 USB Wake up signaling supported on card
+                     * insertion and removal. Must set bit 5 in bmAttributes
+                     * in Configuration descriptor if 100000 is set.
+                     */
+        0xfe, 0x04, 0x11, 0x00,
+                    /*
+                     * u32 dwMaxCCIDMessageLength; For extended APDU in
+                     * [261 + 10 , 65544 + 10]. Otherwise the minimum is
+                     * wMaxPacketSize of the Bulk-OUT endpoint
+                     */
+        0x12, 0x00, 0x01, 0x00,
+        0xFF,       /*
+                     * u8  bClassGetResponse; Significant only for CCID that
+                     * offers an APDU level for exchanges. Indicates the
+                     * default class value used by the CCID when it sends a
+                     * Get Response command to perform the transportation of
+                     * an APDU by T=0 protocol
+                     * FFh indicates that the CCID echos the class of the APDU.
+                     */
+        0xFF,       /*
+                     * u8  bClassEnvelope; EAPDU only. Envelope command for
+                     * T=0
+                     */
+        0x00, 0x00, /*
+                     * u16 wLcdLayout; XXYY Number of lines (XX) and chars per
+                     * line for LCD display used for PIN entry. 0000 - no LCD
+                     */
+        0x01,       /*
+                     * u8  bPINSupport; 01h PIN Verification,
+                     *                  02h PIN Modification
+                     */
+        0x01,       /* u8  bMaxCCIDBusySlots; */
+
+        /* Interrupt-IN endpoint */
+        0x07,       /* u8  ep_bLength; */
+                    /* u8  ep_bDescriptorType; Endpoint */
+        USB_DT_ENDPOINT,
+                    /* u8  ep_bEndpointAddress; IN Endpoint 1 */
+        0x80 | CCID_INT_IN_EP,
+        0x03,       /* u8  ep_bmAttributes; Interrupt */
+                    /* u16 ep_wMaxPacketSize; */
+        CCID_MAX_PACKET_SIZE & 0xff, (CCID_MAX_PACKET_SIZE >> 8),
+        0xff,       /* u8  ep_bInterval; */
+
+        /* Bulk-In endpoint */
+        0x07,       /* u8  ep_bLength; */
+                    /* u8  ep_bDescriptorType; Endpoint */
+        USB_DT_ENDPOINT,
+                    /* u8  ep_bEndpointAddress; IN Endpoint 2 */
+        0x80 | CCID_BULK_IN_EP,
+        0x02,       /* u8  ep_bmAttributes; Bulk */
+        0x40, 0x00, /* u16 ep_wMaxPacketSize; */
+        0x00,       /* u8  ep_bInterval; */
+
+        /* Bulk-Out endpoint */
+        0x07,       /* u8  ep_bLength; */
+                    /* u8  ep_bDescriptorType; Endpoint */
+        USB_DT_ENDPOINT,
+                    /* u8  ep_bEndpointAddress; OUT Endpoint 3 */
+        CCID_BULK_OUT_EP,
+        0x02,       /* u8  ep_bmAttributes; Bulk */
+        0x40, 0x00, /* u16 ep_wMaxPacketSize; */
+        0x00,       /* u8  ep_bInterval; */
+
+};
+
+static bool ccid_has_pending_answers(USBCCIDState *s)
+{
+    return s->pending_answers_num > 0;
+}
+
+static void ccid_clear_pending_answers(USBCCIDState *s)
+{
+    s->pending_answers_num = 0;
+    s->pending_answers_start = 0;
+    s->pending_answers_end = 0;
+}
+
+static void ccid_print_pending_answers(USBCCIDState *s)
+{
+    Answer *answer;
+    int i, count;
+
+    DPRINTF(s, D_VERBOSE, "usb-ccid: pending answers:");
+    if (!ccid_has_pending_answers(s)) {
+        DPRINTF(s, D_VERBOSE, " empty\n");
+        return;
+    }
+    for (i = s->pending_answers_start, count = s->pending_answers_num ;
+         count > 0; count--, i++) {
+        answer = &s->pending_answers[i % PENDING_ANSWERS_NUM];
+        if (count == 1) {
+            DPRINTF(s, D_VERBOSE, "%d:%d\n", answer->slot, answer->seq);
+        } else {
+            DPRINTF(s, D_VERBOSE, "%d:%d,", answer->slot, answer->seq);
+        }
+    }
+}
+
+static void ccid_add_pending_answer(USBCCIDState *s, CCID_Header *hdr)
+{
+    Answer *answer;
+
+    assert(s->pending_answers_num < PENDING_ANSWERS_NUM);
+    s->pending_answers_num++;
+    answer =
+        &s->pending_answers[(s->pending_answers_end++) % PENDING_ANSWERS_NUM];
+    answer->slot = hdr->bSlot;
+    answer->seq = hdr->bSeq;
+    ccid_print_pending_answers(s);
+}
+
+static void ccid_remove_pending_answer(USBCCIDState *s,
+    uint8_t *slot, uint8_t *seq)
+{
+    Answer *answer;
+
+    assert(s->pending_answers_num > 0);
+    s->pending_answers_num--;
+    answer =
+        &s->pending_answers[(s->pending_answers_start++) % PENDING_ANSWERS_NUM];
+    *slot = answer->slot;
+    *seq = answer->seq;
+    ccid_print_pending_answers(s);
+}
+
+static void ccid_bulk_in_clear(USBCCIDState *s)
+{
+    s->bulk_in_pending_start = 0;
+    s->bulk_in_pending_end = 0;
+    s->bulk_in_pending_num = 0;
+}
+
+static void ccid_bulk_in_release(USBCCIDState *s)
+{
+    assert(s->current_bulk_in != NULL);
+    s->current_bulk_in->pos = 0;
+    s->current_bulk_in = NULL;
+}
+
+static void ccid_bulk_in_get(USBCCIDState *s)
+{
+    if (s->current_bulk_in != NULL || s->bulk_in_pending_num == 0) {
+        return;
+    }
+    assert(s->bulk_in_pending_num > 0);
+    s->bulk_in_pending_num--;
+    s->current_bulk_in =
+        &s->bulk_in_pending[(s->bulk_in_pending_start++) % BULK_IN_PENDING_NUM];
+}
+
+static void *ccid_reserve_recv_buf(USBCCIDState *s, uint16_t len)
+{
+    BulkIn *bulk_in;
+
+    DPRINTF(s, D_VERBOSE, "%s: QUEUE: reserve %d bytes\n", __func__, len);
+
+    /* look for an existing element */
+    if (len > BULK_IN_BUF_SIZE) {
+        DPRINTF(s, D_WARN, "usb-ccid.c: %s: len larger then max (%d>%d). "
+                           "discarding message.\n",
+                           __func__, len, BULK_IN_BUF_SIZE);
+        return NULL;
+    }
+    if (s->bulk_in_pending_num >= BULK_IN_PENDING_NUM) {
+        DPRINTF(s, D_WARN, "usb-ccid.c: %s: No free bulk_in buffers. "
+                           "discarding message.\n", __func__);
+        return NULL;
+    }
+    bulk_in =
+        &s->bulk_in_pending[(s->bulk_in_pending_end++) % BULK_IN_PENDING_NUM];
+    s->bulk_in_pending_num++;
+    bulk_in->len = len;
+    return bulk_in->data;
+}
+
+static void ccid_reset(USBCCIDState *s)
+{
+    ccid_bulk_in_clear(s);
+    ccid_clear_pending_answers(s);
+}
+
+static void ccid_detach(USBCCIDState *s)
+{
+    ccid_reset(s);
+}
+
+static void ccid_handle_reset(USBDevice *dev)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+
+    DPRINTF(s, 1, "Reset\n");
+
+    ccid_reset(s);
+}
+
+static int ccid_handle_control(USBDevice *dev, int request, int value,
+                                  int index, int length, uint8_t *data)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+    int ret = 0;
+
+    DPRINTF(s, 1, "got control %x, value %x\n", request, value);
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_STATUS:
+        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
+            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
+        data[1] = 0x00;
+        ret = 2;
+        break;
+    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 0;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 1;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        dev->addr = value;
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+        switch (value >> 8) {
+        case USB_DT_DEVICE:
+            memcpy(data, qemu_ccid_dev_descriptor,
+                   sizeof(qemu_ccid_dev_descriptor));
+            ret = sizeof(qemu_ccid_dev_descriptor);
+            break;
+        case USB_DT_CONFIG:
+            memcpy(data, qemu_ccid_config_descriptor,
+                   sizeof(qemu_ccid_config_descriptor));
+            ret = sizeof(qemu_ccid_config_descriptor);
+            break;
+        case USB_DT_STRING:
+            switch (value & 0xff) {
+            case 0:
+                /* language ids */
+                data[0] = 4;
+                data[1] = 3;
+                data[2] = 0x09;
+                data[3] = 0x04;
+                ret = 4;
+                break;
+            case 1:
+                /* vendor description */
+                ret = set_usb_string(data, CCID_VENDOR_DESCRIPTION);
+                break;
+            case 2:
+                /* product description */
+                ret = set_usb_string(data, CCID_PRODUCT_DESCRIPTION);
+                break;
+            case 3:
+                /* serial number */
+                ret = set_usb_string(data, CCID_SERIAL_NUMBER_STRING);
+                break;
+            case 4:
+                /* interface name */
+                ret = set_usb_string(data, CCID_INTERFACE_NAME);
+                break;
+            default:
+                goto fail;
+            }
+            break;
+        default:
+            goto fail;
+        }
+        break;
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        data[0] = 1;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        /* Only one configuration - we just ignore the request */
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+        ret = 0;
+        break;
+
+        /* Class specific requests.  */
+    case InterfaceOutClass | CCID_CONTROL_ABORT:
+        DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
+        ret = USB_RET_STALL;
+        break;
+    case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
+        DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n");
+        ret = USB_RET_STALL;
+        break;
+    case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES:
+        DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n");
+        ret = USB_RET_STALL;
+        break;
+    default:
+fail:
+        DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
+                request, value);
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static bool ccid_card_inserted(USBCCIDState *s)
+{
+    return s->bmSlotICCState & SLOT_0_STATE_MASK;
+}
+
+static uint8_t ccid_card_status(USBCCIDState *s)
+{
+    return ccid_card_inserted(s)
+            ? (s->powered ?
+                ICC_STATUS_PRESENT_ACTIVE
+              : ICC_STATUS_PRESENT_INACTIVE
+              )
+            : ICC_STATUS_NOT_PRESENT;
+}
+
+static uint8_t ccid_calc_status(USBCCIDState *s)
+{
+    /*
+     * page 55, 6.2.6, calculation of bStatus from bmICCStatus and
+     * bmCommandStatus
+     */
+    uint8_t ret = ccid_card_status(s) | (s->bmCommandStatus << 6);
+    DPRINTF(s, D_VERBOSE, "status = %d\n", ret);
+    return ret;
+}
+
+static void ccid_reset_error_status(USBCCIDState *s)
+{
+    s->bError = ERROR_CMD_NOT_SUPPORTED;
+    s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
+}
+
+static void ccid_write_slot_status(USBCCIDState *s, CCID_Header *recv)
+{
+    CCID_SlotStatus *h = ccid_reserve_recv_buf(s, sizeof(CCID_SlotStatus));
+    if (h == NULL) {
+        return;
+    }
+    h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus;
+    h->b.hdr.dwLength = 0;
+    h->b.hdr.bSlot = recv->bSlot;
+    h->b.hdr.bSeq = recv->bSeq;
+    h->b.bStatus = ccid_calc_status(s);
+    h->b.bError = s->bError;
+    h->bClockStatus = CLOCK_STATUS_RUNNING;
+    ccid_reset_error_status(s);
+}
+
+static void ccid_write_parameters(USBCCIDState *s, CCID_Header *recv)
+{
+    CCID_Parameter *h;
+    uint32_t len = s->ulProtocolDataStructureSize;
+
+    h = ccid_reserve_recv_buf(s, sizeof(CCID_Parameter) + len);
+    if (h == NULL) {
+        return;
+    }
+    h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_Parameters;
+    h->b.hdr.dwLength = 0;
+    h->b.hdr.bSlot = recv->bSlot;
+    h->b.hdr.bSeq = recv->bSeq;
+    h->b.bStatus = ccid_calc_status(s);
+    h->b.bError = s->bError;
+    h->bProtocolNum = s->bProtocolNum;
+    memcpy(h->abProtocolDataStructure, s->abProtocolDataStructure, len);
+    ccid_reset_error_status(s);
+}
+
+static void ccid_write_data_block(USBCCIDState *s, uint8_t slot, uint8_t seq,
+                                  const uint8_t *data, uint32_t len)
+{
+    CCID_DataBlock *p = ccid_reserve_recv_buf(s, sizeof(*p) + len);
+
+    if (p == NULL) {
+        return;
+    }
+    p->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock;
+    p->b.hdr.dwLength = cpu_to_le32(len);
+    p->b.hdr.bSlot = slot;
+    p->b.hdr.bSeq = seq;
+    p->b.bStatus = ccid_calc_status(s);
+    p->b.bError = s->bError;
+    if (p->b.bError) {
+        DPRINTF(s, D_VERBOSE, "error %d", p->b.bError);
+    }
+    memcpy(p->abData, data, len);
+    ccid_reset_error_status(s);
+}
+
+static void ccid_write_data_block_answer(USBCCIDState *s,
+    const uint8_t *data, uint32_t len)
+{
+    uint8_t seq;
+    uint8_t slot;
+
+    if (!ccid_has_pending_answers(s)) {
+        abort();
+    }
+    ccid_remove_pending_answer(s, &slot, &seq);
+    ccid_write_data_block(s, slot, seq, data, len);
+}
+
+static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
+{
+    const uint8_t *atr = NULL;
+    uint32_t len = 0;
+
+    if (s->card) {
+        atr = s->cardinfo->get_atr(s->card, &len);
+    }
+    ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
+}
+
+static void ccid_set_parameters(USBCCIDState *s, CCID_Header *recv)
+{
+    CCID_SetParameters *ph = (CCID_SetParameters *) recv;
+    uint32_t len = 0;
+    if ((ph->bProtocolNum & 3) == 0) {
+        len = 5;
+    }
+    if ((ph->bProtocolNum & 3) == 1) {
+        len = 7;
+    }
+    if (len == 0) {
+        s->bmCommandStatus = COMMAND_STATUS_FAILED;
+        s->bError = 7; /* Protocol invalid or not supported */
+        return;
+    }
+    s->bProtocolNum = ph->bProtocolNum;
+    memcpy(s->abProtocolDataStructure, ph->abProtocolDataStructure, len);
+    s->ulProtocolDataStructureSize = len;
+    DPRINTF(s, 1, "%s: using len %d\n", __func__, len);
+}
+
+/*
+ * must be 5 bytes for T=0, 7 bytes for T=1
+ * See page 52
+ */
+static const uint8_t abDefaultProtocolDataStructure[7] = {
+    0x77, 0x00, 0x00, 0x00, 0x00, 0xfe /*IFSC*/, 0x00 /*NAD*/ };
+
+static void ccid_reset_parameters(USBCCIDState *s)
+{
+   uint32_t len = sizeof(abDefaultProtocolDataStructure);
+
+   s->bProtocolNum = 1; /* T=1 */
+   s->ulProtocolDataStructureSize = len;
+   memcpy(s->abProtocolDataStructure, abDefaultProtocolDataStructure, len);
+}
+
+static void ccid_report_error_failed(USBCCIDState *s, uint8_t error)
+{
+    s->bmCommandStatus = COMMAND_STATUS_FAILED;
+    s->bError = error;
+}
+
+/* NOTE: only a single slot is supported (SLOT_0) */
+static void ccid_on_slot_change(USBCCIDState *s, bool full)
+{
+    /* RDR_to_PC_NotifySlotChange, 6.3.1 page 56 */
+    uint8_t current = s->bmSlotICCState;
+    if (full) {
+        s->bmSlotICCState |= SLOT_0_STATE_MASK;
+    } else {
+        s->bmSlotICCState &= ~SLOT_0_STATE_MASK;
+    }
+    if (current != s->bmSlotICCState) {
+        s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
+    }
+    s->notify_slot_change = true;
+}
+
+static void ccid_write_data_block_error(
+    USBCCIDState *s, uint8_t slot, uint8_t seq)
+{
+    ccid_write_data_block(s, slot, seq, NULL, 0);
+}
+
+static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
+{
+    uint32_t len;
+
+    if (ccid_card_status(s) != ICC_STATUS_PRESENT_ACTIVE) {
+        DPRINTF(s, 1,
+                "usb-ccid: not sending apdu to client, no card connected\n");
+        ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq);
+        return;
+    }
+    len = le32_to_cpu(recv->hdr.dwLength);
+    DPRINTF(s, 1, "%s: seq %d, len %d\n", __func__,
+                recv->hdr.bSeq, len);
+    ccid_add_pending_answer(s, (CCID_Header *)recv);
+    if (s->card) {
+        s->cardinfo->apdu_from_guest(s->card, recv->abData, len);
+    } else {
+        DPRINTF(s, D_WARN, "warning: discarded apdu\n");
+    }
+}
+
+/*
+ * Handle a single USB_TOKEN_OUT, return value returned to guest.
+ * Return value:
+ *  0             - all ok
+ *  USB_RET_STALL - failed to handle packet
+ */
+static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
+{
+    CCID_Header *ccid_header;
+
+    if (p->len + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
+        return USB_RET_STALL;
+    }
+    ccid_header = (CCID_Header *)s->bulk_out_data;
+    memcpy(s->bulk_out_data + s->bulk_out_pos, p->data, p->len);
+    s->bulk_out_pos += p->len;
+    if (p->len == CCID_MAX_PACKET_SIZE) {
+        DPRINTF(s, D_VERBOSE,
+            "usb-ccid: bulk_in: expecting more packets (%d/%d)\n",
+            p->len, ccid_header->dwLength);
+        return 0;
+    }
+    if (s->bulk_out_pos < 10) {
+        DPRINTF(s, 1,
+                "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n",
+                __func__);
+    } else {
+        DPRINTF(s, D_MORE_INFO, "%s %x\n", __func__, ccid_header->bMessageType);
+        switch (ccid_header->bMessageType) {
+        case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus:
+            ccid_write_slot_status(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn:
+            DPRINTF(s, 1, "PowerOn: %d\n",
+                ((CCID_IccPowerOn *)(ccid_header))->bPowerSelect);
+            s->powered = true;
+            if (!ccid_card_inserted(s)) {
+                ccid_report_error_failed(s, ERROR_ICC_MUTE);
+            }
+            /* atr is written regardless of error. */
+            ccid_write_data_block_atr(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff:
+            DPRINTF(s, 1, "PowerOff\n");
+            ccid_reset_error_status(s);
+            s->powered = false;
+            ccid_write_slot_status(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock:
+            ccid_on_apdu_from_guest(s, (CCID_XferBlock *)s->bulk_out_data);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters:
+            ccid_reset_error_status(s);
+            ccid_set_parameters(s, ccid_header);
+            ccid_write_parameters(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters:
+            ccid_reset_error_status(s);
+            ccid_reset_parameters(s);
+            ccid_write_parameters(s, ccid_header);
+            break;
+        case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters:
+            ccid_reset_error_status(s);
+            ccid_write_parameters(s, ccid_header);
+            break;
+        default:
+            DPRINTF(s, 1,
+                "handle_data: ERROR: unhandled message type %Xh\n",
+                ccid_header->bMessageType);
+            /*
+             * The caller is expecting the device to respond, tell it we
+             * don't support the operation.
+             */
+            ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
+            ccid_write_slot_status(s, ccid_header);
+            break;
+        }
+    }
+    s->bulk_out_pos = 0;
+    return 0;
+}
+
+static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len)
+{
+    int ret = 0;
+
+    assert(len > 0);
+    ccid_bulk_in_get(s);
+    if (s->current_bulk_in != NULL) {
+        ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, len);
+        memcpy(data, s->current_bulk_in->data + s->current_bulk_in->pos, ret);
+        s->current_bulk_in->pos += ret;
+        if (s->current_bulk_in->pos == s->current_bulk_in->len) {
+            ccid_bulk_in_release(s);
+        }
+    } else {
+        /* return when device has no data - usb 2.0 spec Table 8-4 */
+        ret = USB_RET_NAK;
+    }
+    if (ret > 0) {
+        DPRINTF(s, D_MORE_INFO,
+                "%s: %d/%d req/act to guest (BULK_IN)\n", __func__, len, ret);
+    }
+    if (ret != USB_RET_NAK && ret < len) {
+        DPRINTF(s, 1,
+            "%s: returning short (EREMOTEIO) %d < %d\n", __func__, ret, len);
+    }
+    return ret;
+}
+
+static int ccid_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+    int ret = 0;
+    uint8_t *data = p->data;
+    int len = p->len;
+
+    switch (p->pid) {
+    case USB_TOKEN_OUT:
+        ret = ccid_handle_bulk_out(s, p);
+        break;
+
+    case USB_TOKEN_IN:
+        switch (p->devep & 0xf) {
+        case CCID_BULK_IN_EP:
+            if (!len) {
+                ret = USB_RET_NAK;
+            } else {
+                ret = ccid_bulk_in_copy_to_guest(s, data, len);
+            }
+            break;
+        case CCID_INT_IN_EP:
+            if (s->notify_slot_change) {
+                /* page 56, RDR_to_PC_NotifySlotChange */
+                data[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
+                data[1] = s->bmSlotICCState;
+                ret = 2;
+                s->notify_slot_change = false;
+                s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
+                DPRINTF(s, D_INFO,
+                        "handle_data: int_in: notify_slot_change %X, "
+                        "requested len %d\n",
+                        s->bmSlotICCState, len);
+            }
+            break;
+        default:
+            DPRINTF(s, 1, "Bad endpoint\n");
+            break;
+        }
+        break;
+    default:
+        DPRINTF(s, 1, "Bad token\n");
+        ret = USB_RET_STALL;
+        break;
+    }
+
+    return ret;
+}
+
+static void ccid_handle_destroy(USBDevice *dev)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+
+    ccid_bulk_in_clear(s);
+}
+
+static void ccid_flush_pending_answers(USBCCIDState *s)
+{
+    while (ccid_has_pending_answers(s)) {
+        ccid_write_data_block_answer(s, NULL, 0);
+    }
+}
+
+static Answer *ccid_peek_next_answer(USBCCIDState *s)
+{
+    return s->pending_answers_num == 0
+        ? NULL
+        : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
+}
+
+static void ccid_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
+{
+    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
+    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info);
+
+    if (info->print) {
+        info->print(mon, card, indent);
+    }
+}
+
+struct CCIDBus {
+    BusState qbus;
+};
+
+static struct BusInfo ccid_bus_info = {
+    .name = "ccid-bus",
+    .size = sizeof(CCIDBus),
+    .print_dev = ccid_bus_dev_print,
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static CCIDBus *ccid_bus_new(DeviceState *dev)
+{
+    CCIDBus *bus;
+
+    bus = FROM_QBUS(CCIDBus, qbus_create(&ccid_bus_info, dev, NULL));
+    bus->qbus.allow_hotplug = 1;
+
+    return bus;
+}
+
+void ccid_card_send_apdu_to_guest(CCIDCardState *card,
+                                  uint8_t *apdu, uint32_t len)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev.qdev,
+                                card->qdev.parent_bus->parent);
+    Answer *answer;
+
+    if (!ccid_has_pending_answers(s)) {
+        DPRINTF(s, 1, "CCID ERROR: got an APDU without pending answers\n");
+        return;
+    }
+    s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
+    answer = ccid_peek_next_answer(s);
+    if (answer == NULL) {
+        abort();
+    }
+    DPRINTF(s, 1, "APDU returned to guest %d (answer seq %d, slot %d)\n",
+        len, answer->seq, answer->slot);
+    ccid_write_data_block_answer(s, apdu, len);
+}
+
+void ccid_card_card_removed(CCIDCardState *card)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    ccid_on_slot_change(s, false);
+    ccid_flush_pending_answers(s);
+    ccid_reset(s);
+}
+
+int ccid_card_ccid_attach(CCIDCardState *card)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    DPRINTF(s, 1, "CCID Attach\n");
+    if (s->migration_state == MIGRATION_MIGRATED) {
+        s->migration_state = MIGRATION_NONE;
+    }
+    return 0;
+}
+
+void ccid_card_ccid_detach(CCIDCardState *card)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    DPRINTF(s, 1, "CCID Detach\n");
+    if (ccid_card_inserted(s)) {
+        ccid_on_slot_change(s, false);
+    }
+    ccid_detach(s);
+}
+
+void ccid_card_card_error(CCIDCardState *card, uint64_t error)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    s->bmCommandStatus = COMMAND_STATUS_FAILED;
+    s->last_answer_error = error;
+    DPRINTF(s, 1, "VSC_Error: %" PRIX64 "\n", s->last_answer_error);
+    /* TODO: these errors should be more verbose and propagated to the guest.*/
+    /*
+     * We flush all pending answers on CardRemove message in ccid-card-passthru,
+     * so check that first to not trigger abort
+     */
+    if (ccid_has_pending_answers(s)) {
+        ccid_write_data_block_answer(s, NULL, 0);
+    }
+}
+
+void ccid_card_card_inserted(CCIDCardState *card)
+{
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
+    ccid_flush_pending_answers(s);
+    ccid_on_slot_change(s, true);
+}
+
+static int ccid_card_exit(DeviceState *qdev)
+{
+    int ret = 0;
+    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
+    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info);
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+
+    if (ccid_card_inserted(s)) {
+        ccid_card_card_removed(card);
+    }
+    if (info->exitfn) {
+        ret = info->exitfn(card);
+    }
+    s->card = NULL;
+    s->cardinfo = NULL;
+    return ret;
+}
+
+static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
+{
+    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
+    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, base);
+    USBCCIDState *s =
+        DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
+    int ret = 0;
+
+    if (card->slot != 0) {
+        error_report("Warning: usb-ccid supports one slot, can't add %d",
+                card->slot);
+        return -1;
+    }
+    if (s->card != NULL) {
+        error_report("Warning: usb-ccid card already full, not adding\n");
+        return -1;
+    }
+    ret = info->initfn ? info->initfn(card) : ret;
+    if (ret == 0) {
+        s->card = card;
+        s->cardinfo = info;
+    }
+    return ret;
+}
+
+void ccid_card_qdev_register(CCIDCardInfo *card)
+{
+    card->qdev.bus_info = &ccid_bus_info;
+    card->qdev.init = ccid_card_init;
+    card->qdev.exit = ccid_card_exit;
+    qdev_register(&card->qdev);
+}
+
+static int ccid_initfn(USBDevice *dev)
+{
+    USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+
+    s->bus = ccid_bus_new(&dev->qdev);
+    s->card = NULL;
+    s->cardinfo = NULL;
+    s->migration_state = MIGRATION_NONE;
+    s->migration_target_ip = 0;
+    s->migration_target_port = 0;
+    s->dev.speed = USB_SPEED_FULL;
+    s->notify_slot_change = false;
+    s->powered = true;
+    s->pending_answers_num = 0;
+    s->last_answer_error = 0;
+    s->bulk_in_pending_start = 0;
+    s->bulk_in_pending_end = 0;
+    s->current_bulk_in = NULL;
+    ccid_reset_error_status(s);
+    s->bulk_out_pos = 0;
+    ccid_reset_parameters(s);
+    ccid_reset(s);
+    return 0;
+}
+
+static int ccid_post_load(void *opaque, int version_id)
+{
+    USBCCIDState *s = opaque;
+
+    /*
+     * This must be done after usb_device_attach, which sets state to ATTACHED,
+     * while it must be DEFAULT in order to accept packets (like it is after
+     * reset, but reset will reset our addr and call our reset handler which
+     * may change state, and we don't want to do that when migrating).
+     */
+    s->dev.state = s->state_vmstate;
+    return 0;
+}
+
+static void ccid_pre_save(void *opaque)
+{
+    USBCCIDState *s = opaque;
+
+    s->state_vmstate = s->dev.state;
+    if (s->dev.attached) {
+        /*
+         * Migrating an open device, ignore reconnection CHR_EVENT to avoid an
+         * erroneous detach.
+         */
+        s->migration_state = MIGRATION_MIGRATED;
+    }
+}
+
+static VMStateDescription bulk_in_vmstate = {
+    .name = "CCID BulkIn state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BUFFER(data, BulkIn),
+        VMSTATE_UINT32(len, BulkIn),
+        VMSTATE_UINT32(pos, BulkIn),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription answer_vmstate = {
+    .name = "CCID Answer state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(slot, Answer),
+        VMSTATE_UINT8(seq, Answer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription usb_device_vmstate = {
+    .name = "usb_device",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(addr, USBDevice),
+        VMSTATE_BUFFER(setup_buf, USBDevice),
+        VMSTATE_BUFFER(data_buf, USBDevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription ccid_vmstate = {
+    .name = CCID_DEV_NAME,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = ccid_post_load,
+    .pre_save = ccid_pre_save,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(dev, USBCCIDState, 1, usb_device_vmstate, USBDevice),
+        VMSTATE_UINT8(debug, USBCCIDState),
+        VMSTATE_BUFFER(bulk_out_data, USBCCIDState),
+        VMSTATE_UINT32(bulk_out_pos, USBCCIDState),
+        VMSTATE_UINT8(bmSlotICCState, USBCCIDState),
+        VMSTATE_UINT8(powered, USBCCIDState),
+        VMSTATE_UINT8(notify_slot_change, USBCCIDState),
+        VMSTATE_UINT64(last_answer_error, USBCCIDState),
+        VMSTATE_UINT8(bError, USBCCIDState),
+        VMSTATE_UINT8(bmCommandStatus, USBCCIDState),
+        VMSTATE_UINT8(bProtocolNum, USBCCIDState),
+        VMSTATE_BUFFER(abProtocolDataStructure, USBCCIDState),
+        VMSTATE_UINT32(ulProtocolDataStructureSize, USBCCIDState),
+        VMSTATE_STRUCT_ARRAY(bulk_in_pending, USBCCIDState,
+                       BULK_IN_PENDING_NUM, 1, bulk_in_vmstate, BulkIn),
+        VMSTATE_UINT32(bulk_in_pending_start, USBCCIDState),
+        VMSTATE_UINT32(bulk_in_pending_end, USBCCIDState),
+        VMSTATE_STRUCT_ARRAY(pending_answers, USBCCIDState,
+                        PENDING_ANSWERS_NUM, 1, answer_vmstate, Answer),
+        VMSTATE_UINT32(pending_answers_num, USBCCIDState),
+        VMSTATE_UINT8(migration_state, USBCCIDState),
+        VMSTATE_UINT32(state_vmstate, USBCCIDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static struct USBDeviceInfo ccid_info = {
+    .product_desc   = "QEMU USB CCID",
+    .qdev.name      = CCID_DEV_NAME,
+    .qdev.desc      = "CCID Rev 1.1 smartcard reader",
+    .qdev.size      = sizeof(USBCCIDState),
+    .init           = ccid_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = ccid_handle_reset,
+    .handle_control = ccid_handle_control,
+    .handle_data    = ccid_handle_data,
+    .handle_destroy = ccid_handle_destroy,
+    .usbdevice_name = "ccid",
+    .qdev.props     = (Property[]) {
+        DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .qdev.vmsd      = &ccid_vmstate,
+};
+
+static void ccid_register_devices(void)
+{
+    usb_qdev_register(&ccid_info);
+}
+device_init(ccid_register_devices)
index c25362cc95eac167f68a0f8e360b011e29205379..89c293c466aba43fdc29d510db012899a27176dc 100644 (file)
@@ -26,7 +26,7 @@
 #include "console.h"
 #include "usb.h"
 #include "usb-desc.h"
-#include "sysemu.h"
+#include "qemu-timer.h"
 
 /* HID interface requests */
 #define GET_REPORT   0xa101
index 76f5b027b2d277517ef2f5ec8d8f7b0a117efd31..947fd3f83c6975340b42241fd892946d3cda5b31 100644 (file)
@@ -33,7 +33,7 @@ do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
 
 enum USBMSDMode {
     USB_MSDM_CBW, /* Command Block.  */
-    USB_MSDM_DATAOUT, /* Tranfer data to device.  */
+    USB_MSDM_DATAOUT, /* Transfer data to device.  */
     USB_MSDM_DATAIN, /* Transfer data from device.  */
     USB_MSDM_CSW /* Command Status.  */
 };
@@ -253,7 +253,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
         usb_msd_copy_data(s);
         if (s->usb_len == 0) {
             /* Set s->packet to NULL before calling usb_packet_complete
-               because annother request may be issued before
+               because another request may be issued before
                usb_packet_complete returns.  */
             DPRINTF("Packet complete %p\n", p);
             s->packet = NULL;
index 73d47b845b6b73ed771f1fab8bcd2042fca68f50..d21c82028267c8482fe5db972af94f41f45fa9b0 100644 (file)
@@ -427,7 +427,7 @@ static inline int get_dwords(OHCIState *ohci,
     addr += ohci->localmem_base;
 
     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
-        cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
+        cpu_physical_memory_read(addr, buf, sizeof(*buf));
         *buf = le32_to_cpu(*buf);
     }
 
@@ -444,7 +444,7 @@ static inline int put_dwords(OHCIState *ohci,
 
     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
         uint32_t tmp = cpu_to_le32(*buf);
-        cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
+        cpu_physical_memory_write(addr, &tmp, sizeof(tmp));
     }
 
     return 1;
@@ -459,7 +459,7 @@ static inline int get_words(OHCIState *ohci,
     addr += ohci->localmem_base;
 
     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
-        cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
+        cpu_physical_memory_read(addr, buf, sizeof(*buf));
         *buf = le16_to_cpu(*buf);
     }
 
@@ -476,7 +476,7 @@ static inline int put_words(OHCIState *ohci,
 
     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
         uint16_t tmp = cpu_to_le16(*buf);
-        cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
+        cpu_physical_memory_write(addr, &tmp, sizeof(tmp));
     }
 
     return 1;
@@ -504,8 +504,7 @@ static inline int ohci_read_iso_td(OHCIState *ohci,
 static inline int ohci_read_hcca(OHCIState *ohci,
                                  uint32_t addr, struct ohci_hcca *hcca)
 {
-    cpu_physical_memory_rw(addr + ohci->localmem_base,
-                           (uint8_t *)hcca, sizeof(*hcca), 0);
+    cpu_physical_memory_read(addr + ohci->localmem_base, hcca, sizeof(*hcca));
     return 1;
 }
 
@@ -531,8 +530,7 @@ static inline int ohci_put_iso_td(OHCIState *ohci,
 static inline int ohci_put_hcca(OHCIState *ohci,
                                 uint32_t addr, struct ohci_hcca *hcca)
 {
-    cpu_physical_memory_rw(addr + ohci->localmem_base,
-                           (uint8_t *)hcca, sizeof(*hcca), 1);
+    cpu_physical_memory_write(addr + ohci->localmem_base, hcca, sizeof(*hcca));
     return 1;
 }
 
index 9f1bfcf94143762f66b39747cdb96491767c9882..46b6a3f383e9249950c2877a5999d8c541f4dac9 100644 (file)
@@ -223,7 +223,7 @@ static void versatile_init(ram_addr_t ram_size,
     for(n = 0; n < nb_nics; n++) {
         nd = &nd_table[n];
 
-        if ((!nd->model && !done_smc) || strcmp(nd->model, "smc91c111") == 0) {
+        if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
             smc91c111_init(nd, 0x10010000, sic[25]);
             done_smc = 1;
         } else {
diff --git a/hw/vexpress.c b/hw/vexpress.c
new file mode 100644 (file)
index 0000000..9ffd332
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * ARM Versatile Express emulation.
+ *
+ * Copyright (c) 2010 - 2011 B Labs Ltd.
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Bahadir Balban, Amit Mahajan, Peter Maydell
+ *
+ *  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.
+ *
+ *  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 "sysbus.h"
+#include "arm-misc.h"
+#include "primecell.h"
+#include "devices.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+
+#define SMP_BOOT_ADDR 0xe0000000
+
+#define VEXPRESS_BOARD_ID 0x8e0
+
+static struct arm_boot_info vexpress_binfo = {
+    .smp_loader_start = SMP_BOOT_ADDR,
+};
+
+static void vexpress_a9_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env = NULL;
+    ram_addr_t ram_offset, vram_offset, sram_offset;
+    DeviceState *dev, *sysctl;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    qemu_irq pic[64];
+    int n;
+    qemu_irq cpu_irq[4];
+    uint32_t proc_id;
+    uint32_t sys_id;
+    ram_addr_t low_ram_size, vram_size, sram_size;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a9";
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        irqp = arm_pic_init_cpu(env);
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+    }
+
+    if (ram_size > 0x40000000) {
+        /* 1GB is the maximum the address space permits */
+        fprintf(stderr, "vexpress: cannot model more than 1GB RAM\n");
+        exit(1);
+    }
+
+    ram_offset = qemu_ram_alloc(NULL, "vexpress.highmem", ram_size);
+    low_ram_size = ram_size;
+    if (low_ram_size > 0x4000000) {
+        low_ram_size = 0x4000000;
+    }
+    /* RAM is from 0x60000000 upwards. The bottom 64MB of the
+     * address space should in theory be remappable to various
+     * things including ROM or RAM; we always map the RAM there.
+     */
+    cpu_register_physical_memory(0x0, low_ram_size, ram_offset | IO_MEM_RAM);
+    cpu_register_physical_memory(0x60000000, ram_size,
+                                 ram_offset | IO_MEM_RAM);
+
+    /* 0x1e000000 A9MPCore (SCU) private memory region */
+    dev = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    vexpress_binfo.smp_priv_base = 0x1e000000;
+    sysbus_mmio_map(busdev, 0, vexpress_binfo.smp_priv_base);
+    for (n = 0; n < smp_cpus; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
+    /* Interrupts [42:0] are from the motherboard;
+     * [47:43] are reserved; [63:48] are daughterboard
+     * peripherals. Note that some documentation numbers
+     * external interrupts starting from 32 (because the
+     * A9MP has internal interrupts 0..31).
+     */
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* Motherboard peripherals CS7 : 0x10000000 .. 0x10020000 */
+    sys_id = 0x1190f500;
+    proc_id = 0x0c000191;
+
+    /* 0x10000000 System registers */
+    sysctl = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
+    qdev_init_nofail(sysctl);
+    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
+
+    /* 0x10001000 SP810 system control */
+    /* 0x10002000 serial bus PCI */
+    /* 0x10004000 PL041 audio */
+
+    dev = sysbus_create_varargs("pl181", 0x10005000, pic[9], pic[10], NULL);
+    /* Wire up MMC card detect and read-only signals */
+    qdev_connect_gpio_out(dev, 0,
+                          qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
+    qdev_connect_gpio_out(dev, 1,
+                          qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
+
+    sysbus_create_simple("pl050_keyboard", 0x10006000, pic[12]);
+    sysbus_create_simple("pl050_mouse", 0x10007000, pic[13]);
+
+    sysbus_create_simple("pl011", 0x10009000, pic[5]);
+    sysbus_create_simple("pl011", 0x1000a000, pic[6]);
+    sysbus_create_simple("pl011", 0x1000b000, pic[7]);
+    sysbus_create_simple("pl011", 0x1000c000, pic[8]);
+
+    /* 0x1000f000 SP805 WDT */
+
+    sysbus_create_simple("sp804", 0x10011000, pic[2]);
+    sysbus_create_simple("sp804", 0x10012000, pic[3]);
+
+    /* 0x10016000 Serial Bus DVI */
+
+    sysbus_create_simple("pl031", 0x10017000, pic[4]); /* RTC */
+
+    /* 0x1001a000 Compact Flash */
+
+    /* 0x1001f000 PL111 CLCD (motherboard) */
+
+    /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
+
+    /* 0x10020000 PL111 CLCD (daughterboard) */
+    sysbus_create_simple("pl110", 0x10020000, pic[44]);
+
+    /* 0x10060000 AXI RAM */
+    /* 0x100e0000 PL341 Dynamic Memory Controller */
+    /* 0x100e1000 PL354 Static Memory Controller */
+    /* 0x100e2000 System Configuration Controller */
+
+    sysbus_create_simple("sp804", 0x100e4000, pic[48]);
+    /* 0x100e5000 SP805 Watchdog module */
+    /* 0x100e6000 BP147 TrustZone Protection Controller */
+    /* 0x100e9000 PL301 'Fast' AXI matrix */
+    /* 0x100ea000 PL301 'Slow' AXI matrix */
+    /* 0x100ec000 TrustZone Address Space Controller */
+    /* 0x10200000 CoreSight debug APB */
+    /* 0x1e00a000 PL310 L2 Cache Controller */
+
+    /* CS0: NOR0 flash          : 0x40000000 .. 0x44000000 */
+    /* CS4: NOR1 flash          : 0x44000000 .. 0x48000000 */
+    /* CS2: SRAM                : 0x48000000 .. 0x4a000000 */
+    sram_size = 0x2000000;
+    sram_offset = qemu_ram_alloc(NULL, "vexpress.sram", sram_size);
+    cpu_register_physical_memory(0x48000000, sram_size,
+                                 sram_offset | IO_MEM_RAM);
+
+    /* CS3: USB, ethernet, VRAM : 0x4c000000 .. 0x50000000 */
+
+    /* 0x4c000000 Video RAM */
+    vram_size = 0x800000;
+    vram_offset = qemu_ram_alloc(NULL, "vexpress.vram", vram_size);
+    cpu_register_physical_memory(0x4c000000, vram_size,
+                                 vram_offset | IO_MEM_RAM);
+
+    /* 0x4e000000 LAN9118 Ethernet */
+    if (nd_table[0].vlan) {
+        lan9118_init(&nd_table[0], 0x4e000000, pic[15]);
+    }
+
+    /* 0x4f000000 ISP1761 USB */
+
+    /* ??? Hack to map an additional page of ram for the secondary CPU
+       startup code.  I guess this works on real hardware because the
+       BootROM happens to be in ROM/flash or in memory that isn't clobbered
+       until after Linux boots the secondary CPUs.  */
+    ram_offset = qemu_ram_alloc(NULL, "vexpress.hack", 0x1000);
+    cpu_register_physical_memory(SMP_BOOT_ADDR, 0x1000,
+                                 ram_offset | IO_MEM_RAM);
+
+    vexpress_binfo.ram_size = ram_size;
+    vexpress_binfo.kernel_filename = kernel_filename;
+    vexpress_binfo.kernel_cmdline = kernel_cmdline;
+    vexpress_binfo.initrd_filename = initrd_filename;
+    vexpress_binfo.nb_cpus = smp_cpus;
+    vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
+    vexpress_binfo.loader_start = 0x60000000;
+    arm_load_kernel(first_cpu, &vexpress_binfo);
+}
+
+
+static QEMUMachine vexpress_a9_machine = {
+    .name = "vexpress-a9",
+    .desc = "ARM Versatile Express for Cortex-A9",
+    .init = vexpress_a9_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
+static void vexpress_machine_init(void)
+{
+    qemu_register_machine(&vexpress_a9_machine);
+}
+
+machine_init(vexpress_machine_init);
diff --git a/hw/virtio-9p-debug.c b/hw/virtio-9p-debug.c
deleted file mode 100644 (file)
index 6b18842..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * Virtio 9p PDU debug
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-#include "virtio.h"
-#include "pc.h"
-#include "virtio-9p.h"
-#include "virtio-9p-debug.h"
-
-#define BUG_ON(cond) assert(!(cond))
-
-static FILE *llogfile;
-
-static struct iovec *get_sg(V9fsPDU *pdu, int rx)
-{
-    if (rx) {
-        return pdu->elem.in_sg;
-    }
-    return pdu->elem.out_sg;
-}
-
-static int get_sg_count(V9fsPDU *pdu, int rx)
-{
-    if (rx) {
-        return pdu->elem.in_num;
-    }
-    return pdu->elem.out_num;
-
-}
-
-static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp,
-                        const char *name)
-{
-    size_t copied;
-    int count = get_sg_count(pdu, rx);
-    size_t offset = *offsetp;
-    struct iovec *sg = get_sg(pdu, rx);
-    int8_t value;
-
-    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
-
-    BUG_ON(copied != sizeof(value));
-    offset += sizeof(value);
-    fprintf(llogfile, "%s=0x%x", name, value);
-    *offsetp = offset;
-}
-
-static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp,
-                        const char *name)
-{
-    size_t copied;
-    int count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    int16_t value;
-
-
-    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
-
-    BUG_ON(copied != sizeof(value));
-    offset += sizeof(value);
-    fprintf(llogfile, "%s=0x%x", name, value);
-    *offsetp = offset;
-}
-
-static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp,
-                        const char *name)
-{
-    size_t copied;
-    int count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    int32_t value;
-
-
-    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
-
-    BUG_ON(copied != sizeof(value));
-    offset += sizeof(value);
-    fprintf(llogfile, "%s=0x%x", name, value);
-    *offsetp = offset;
-}
-
-static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp,
-                        const char *name)
-{
-    size_t copied;
-    int count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    int64_t value;
-
-
-    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
-
-    BUG_ON(copied != sizeof(value));
-    offset += sizeof(value);
-    fprintf(llogfile, "%s=0x%" PRIx64, name, value);
-    *offsetp = offset;
-}
-
-static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    int sg_count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    uint16_t tmp_size, size;
-    size_t result;
-    size_t copied = 0;
-    int i = 0;
-
-    /* get the size */
-    copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size));
-    BUG_ON(copied != sizeof(tmp_size));
-    size = le16_to_cpupu(&tmp_size);
-    offset += copied;
-
-    fprintf(llogfile, "%s=", name);
-    for (i = 0; size && i < sg_count; i++) {
-        size_t len;
-        if (offset >= sg[i].iov_len) {
-            /* skip this sg */
-            offset -= sg[i].iov_len;
-            continue;
-        } else {
-            len = MIN(sg[i].iov_len - offset, size);
-            result = fwrite(sg[i].iov_base + offset, 1, len, llogfile);
-            BUG_ON(result != len);
-            size -= len;
-            copied += len;
-            if (size) {
-                offset = 0;
-                continue;
-            }
-        }
-    }
-    *offsetp += copied;
-}
-
-static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    fprintf(llogfile, "%s={", name);
-    pprint_int8(pdu, rx, offsetp, "type");
-    pprint_int32(pdu, rx, offsetp, ", version");
-    pprint_int64(pdu, rx, offsetp, ", path");
-    fprintf(llogfile, "}");
-}
-
-static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    fprintf(llogfile, "%s={", name);
-    pprint_int16(pdu, rx, offsetp, "size");
-    pprint_int16(pdu, rx, offsetp, ", type");
-    pprint_int32(pdu, rx, offsetp, ", dev");
-    pprint_qid(pdu, rx, offsetp, ", qid");
-    pprint_int32(pdu, rx, offsetp, ", mode");
-    pprint_int32(pdu, rx, offsetp, ", atime");
-    pprint_int32(pdu, rx, offsetp, ", mtime");
-    pprint_int64(pdu, rx, offsetp, ", length");
-    pprint_str(pdu, rx, offsetp, ", name");
-    pprint_str(pdu, rx, offsetp, ", uid");
-    pprint_str(pdu, rx, offsetp, ", gid");
-    pprint_str(pdu, rx, offsetp, ", muid");
-    pprint_str(pdu, rx, offsetp, ", extension");
-    pprint_int32(pdu, rx, offsetp, ", uid");
-    pprint_int32(pdu, rx, offsetp, ", gid");
-    pprint_int32(pdu, rx, offsetp, ", muid");
-    fprintf(llogfile, "}");
-}
-
-static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp,
-                                                  const char *name)
-{
-    fprintf(llogfile, "%s={", name);
-    pprint_qid(pdu, rx, offsetp, "qid");
-    pprint_int32(pdu, rx, offsetp, ", st_mode");
-    pprint_int64(pdu, rx, offsetp, ", st_nlink");
-    pprint_int32(pdu, rx, offsetp, ", st_uid");
-    pprint_int32(pdu, rx, offsetp, ", st_gid");
-    pprint_int64(pdu, rx, offsetp, ", st_rdev");
-    pprint_int64(pdu, rx, offsetp, ", st_size");
-    pprint_int64(pdu, rx, offsetp, ", st_blksize");
-    pprint_int64(pdu, rx, offsetp, ", st_blocks");
-    pprint_int64(pdu, rx, offsetp, ", atime");
-    pprint_int64(pdu, rx, offsetp, ", atime_nsec");
-    pprint_int64(pdu, rx, offsetp, ", mtime");
-    pprint_int64(pdu, rx, offsetp, ", mtime_nsec");
-    pprint_int64(pdu, rx, offsetp, ", ctime");
-    pprint_int64(pdu, rx, offsetp, ", ctime_nsec");
-    fprintf(llogfile, "}");
-}
-
-
-
-static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    int sg_count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    uint16_t tmp_count, count, i;
-    size_t copied = 0;
-
-    fprintf(llogfile, "%s={", name);
-
-    /* Get the count */
-    copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
-    BUG_ON(copied != sizeof(tmp_count));
-    count = le16_to_cpupu(&tmp_count);
-    offset += copied;
-
-    for (i = 0; i < count; i++) {
-        char str[512];
-        if (i) {
-            fprintf(llogfile, ", ");
-        }
-        snprintf(str, sizeof(str), "[%d]", i);
-        pprint_str(pdu, rx, &offset, str);
-    }
-
-    fprintf(llogfile, "}");
-
-    *offsetp = offset;
-}
-
-static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    int sg_count = get_sg_count(pdu, rx);
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    uint16_t tmp_count, count, i;
-    size_t copied = 0;
-
-    fprintf(llogfile, "%s={", name);
-
-    copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
-    BUG_ON(copied != sizeof(tmp_count));
-    count = le16_to_cpupu(&tmp_count);
-    offset += copied;
-
-    for (i = 0; i < count; i++) {
-        char str[512];
-        if (i) {
-            fprintf(llogfile, ", ");
-        }
-        snprintf(str, sizeof(str), "[%d]", i);
-        pprint_qid(pdu, rx, &offset, str);
-    }
-
-    fprintf(llogfile, "}");
-
-    *offsetp = offset;
-}
-
-static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    struct iovec *sg = get_sg(pdu, rx);
-    unsigned int count;
-    int i;
-
-    if (rx) {
-        count = pdu->elem.in_num;
-    } else {
-        count = pdu->elem.out_num;
-    }
-
-    fprintf(llogfile, "%s={", name);
-    for (i = 0; i < count; i++) {
-        if (i) {
-            fprintf(llogfile, ", ");
-        }
-        fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len);
-    }
-    fprintf(llogfile, "}");
-}
-
-/* FIXME: read from a directory fid returns serialized stat_t's */
-#ifdef DEBUG_DATA
-static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
-{
-    struct iovec *sg = get_sg(pdu, rx);
-    size_t offset = *offsetp;
-    unsigned int count;
-    int32_t size;
-    int total, i, j;
-    ssize_t len;
-
-    if (rx) {
-        count = pdu->elem.in_num;
-    } else
-        count = pdu->elem.out_num;
-    }
-
-    BUG_ON((offset + sizeof(size)) > sg[0].iov_len);
-
-    memcpy(&size, sg[0].iov_base + offset, sizeof(size));
-    offset += sizeof(size);
-
-    fprintf(llogfile, "size: %x\n", size);
-
-    sg[0].iov_base += 11; /* skip header */
-    sg[0].iov_len -= 11;
-
-    total = 0;
-    for (i = 0; i < count; i++) {
-        total += sg[i].iov_len;
-        if (total >= size) {
-            /* trim sg list so writev does the right thing */
-            sg[i].iov_len -= (total - size);
-            i++;
-            break;
-        }
-    }
-
-    fprintf(llogfile, "%s={\"", name);
-    fflush(llogfile);
-    for (j = 0; j < i; j++) {
-        if (j) {
-            fprintf(llogfile, "\", \"");
-            fflush(llogfile);
-        }
-
-        do {
-            len = writev(fileno(llogfile), &sg[j], 1);
-        } while (len == -1 && errno == EINTR);
-        fprintf(llogfile, "len == %ld: %m\n", len);
-        BUG_ON(len != sg[j].iov_len);
-    }
-    fprintf(llogfile, "\"}");
-
-    sg[0].iov_base -= 11;
-    sg[0].iov_len += 11;
-
-}
-#endif
-
-void pprint_pdu(V9fsPDU *pdu)
-{
-    size_t offset = 7;
-
-    if (llogfile == NULL) {
-        llogfile = fopen("/tmp/pdu.log", "w");
-    }
-
-    BUG_ON(!llogfile);
-
-    switch (pdu->id) {
-    case P9_TREADDIR:
-        fprintf(llogfile, "TREADDIR: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int64(pdu, 0, &offset, ", initial offset");
-        pprint_int32(pdu, 0, &offset, ", max count");
-        break;
-    case P9_RREADDIR:
-        fprintf(llogfile, "RREADDIR: (");
-        pprint_int32(pdu, 1, &offset, "count");
-#ifdef DEBUG_DATA
-        pprint_data(pdu, 1, &offset, ", data");
-#endif
-        break;
-    case P9_TMKDIR:
-        fprintf(llogfile, "TMKDIR: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, "name");
-        pprint_int32(pdu, 0, &offset, "mode");
-        pprint_int32(pdu, 0, &offset, "gid");
-        break;
-    case P9_RMKDIR:
-        fprintf(llogfile, "RMKDIR: (");
-        pprint_qid(pdu, 0, &offset, "qid");
-        break;
-    case P9_TVERSION:
-        fprintf(llogfile, "TVERSION: (");
-        pprint_int32(pdu, 0, &offset, "msize");
-        pprint_str(pdu, 0, &offset, ", version");
-        break;
-    case P9_RVERSION:
-        fprintf(llogfile, "RVERSION: (");
-        pprint_int32(pdu, 1, &offset, "msize");
-        pprint_str(pdu, 1, &offset, ", version");
-        break;
-    case P9_TGETATTR:
-        fprintf(llogfile, "TGETATTR: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RGETATTR:
-        fprintf(llogfile, "RGETATTR: (");
-        pprint_stat_dotl(pdu, 1, &offset, "getattr");
-        break;
-    case P9_TAUTH:
-        fprintf(llogfile, "TAUTH: (");
-        pprint_int32(pdu, 0, &offset, "afid");
-        pprint_str(pdu, 0, &offset, ", uname");
-        pprint_str(pdu, 0, &offset, ", aname");
-        pprint_int32(pdu, 0, &offset, ", n_uname");
-        break;
-    case P9_RAUTH:
-        fprintf(llogfile, "RAUTH: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        break;
-    case P9_TATTACH:
-        fprintf(llogfile, "TATTACH: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int32(pdu, 0, &offset, ", afid");
-        pprint_str(pdu, 0, &offset, ", uname");
-        pprint_str(pdu, 0, &offset, ", aname");
-        pprint_int32(pdu, 0, &offset, ", n_uname");
-        break;
-    case P9_RATTACH:
-        fprintf(llogfile, "RATTACH: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        break;
-    case P9_TERROR:
-        fprintf(llogfile, "TERROR: (");
-        break;
-    case P9_RERROR:
-        fprintf(llogfile, "RERROR: (");
-        pprint_str(pdu, 1, &offset, "ename");
-        pprint_int32(pdu, 1, &offset, ", ecode");
-        break;
-    case P9_TFLUSH:
-        fprintf(llogfile, "TFLUSH: (");
-        pprint_int16(pdu, 0, &offset, "oldtag");
-        break;
-    case P9_RFLUSH:
-        fprintf(llogfile, "RFLUSH: (");
-        break;
-    case P9_TWALK:
-        fprintf(llogfile, "TWALK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int32(pdu, 0, &offset, ", newfid");
-        pprint_strs(pdu, 0, &offset, ", wnames");
-        break;
-    case P9_RWALK:
-        fprintf(llogfile, "RWALK: (");
-        pprint_qids(pdu, 1, &offset, "wqids");
-        break;
-    case P9_TOPEN:
-        fprintf(llogfile, "TOPEN: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int8(pdu, 0, &offset, ", mode");
-        break;
-    case P9_ROPEN:
-        fprintf(llogfile, "ROPEN: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        pprint_int32(pdu, 1, &offset, ", iounit");
-        break;
-    case P9_TCREATE:
-        fprintf(llogfile, "TCREATE: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, ", name");
-        pprint_int32(pdu, 0, &offset, ", perm");
-        pprint_int8(pdu, 0, &offset, ", mode");
-        pprint_str(pdu, 0, &offset, ", extension");
-        break;
-    case P9_RCREATE:
-        fprintf(llogfile, "RCREATE: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        pprint_int32(pdu, 1, &offset, ", iounit");
-        break;
-    case P9_TSYMLINK:
-        fprintf(llogfile, "TSYMLINK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, ", name");
-        pprint_str(pdu, 0, &offset, ", symname");
-        pprint_int32(pdu, 0, &offset, ", gid");
-        break;
-    case P9_RSYMLINK:
-        fprintf(llogfile, "RSYMLINK: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        break;
-    case P9_TLCREATE:
-        fprintf(llogfile, "TLCREATE: (");
-        pprint_int32(pdu, 0, &offset, "dfid");
-        pprint_str(pdu, 0, &offset, ", name");
-        pprint_int32(pdu, 0, &offset, ", flags");
-        pprint_int32(pdu, 0, &offset, ", mode");
-        pprint_int32(pdu, 0, &offset, ", gid");
-        break;
-    case P9_RLCREATE:
-        fprintf(llogfile, "RLCREATE: (");
-        pprint_qid(pdu, 1, &offset, "qid");
-        pprint_int32(pdu, 1, &offset, ", iounit");
-        break;
-    case P9_TMKNOD:
-       fprintf(llogfile, "TMKNOD: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, "name");
-        pprint_int32(pdu, 0, &offset, "mode");
-        pprint_int32(pdu, 0, &offset, "major");
-        pprint_int32(pdu, 0, &offset, "minor");
-        pprint_int32(pdu, 0, &offset, "gid");
-        break;
-    case P9_RMKNOD:
-        fprintf(llogfile, "RMKNOD: )");
-        pprint_qid(pdu, 0, &offset, "qid");
-        break;
-    case P9_TREADLINK:
-       fprintf(llogfile, "TREADLINK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RREADLINK:
-       fprintf(llogfile, "RREADLINK: (");
-        pprint_str(pdu, 0, &offset, "target");
-        break;
-    case P9_TREAD:
-        fprintf(llogfile, "TREAD: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int64(pdu, 0, &offset, ", offset");
-        pprint_int32(pdu, 0, &offset, ", count");
-        pprint_sg(pdu, 0, &offset, ", sg");
-        break;
-    case P9_RREAD:
-        fprintf(llogfile, "RREAD: (");
-        pprint_int32(pdu, 1, &offset, "count");
-        pprint_sg(pdu, 1, &offset, ", sg");
-        offset = 7;
-#ifdef DEBUG_DATA
-        pprint_data(pdu, 1, &offset, ", data");
-#endif
-        break;
-    case P9_TWRITE:
-        fprintf(llogfile, "TWRITE: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int64(pdu, 0, &offset, ", offset");
-        pprint_int32(pdu, 0, &offset, ", count");
-        break;
-    case P9_RWRITE:
-        fprintf(llogfile, "RWRITE: (");
-        pprint_int32(pdu, 1, &offset, "count");
-        break;
-    case P9_TCLUNK:
-        fprintf(llogfile, "TCLUNK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RCLUNK:
-        fprintf(llogfile, "RCLUNK: (");
-        break;
-    case P9_TFSYNC:
-        fprintf(llogfile, "TFSYNC: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RFSYNC:
-        fprintf(llogfile, "RFSYNC: (");
-        break;
-    case P9_TLINK:
-        fprintf(llogfile, "TLINK: (");
-        pprint_int32(pdu, 0, &offset, "dfid");
-        pprint_int32(pdu, 0, &offset, ", fid");
-        pprint_str(pdu, 0, &offset, ", newpath");
-        break;
-    case P9_RLINK:
-        fprintf(llogfile, "RLINK: (");
-        break;
-    case P9_TREMOVE:
-        fprintf(llogfile, "TREMOVE: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RREMOVE:
-        fprintf(llogfile, "RREMOVE: (");
-        break;
-    case P9_TSTAT:
-        fprintf(llogfile, "TSTAT: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        break;
-    case P9_RSTAT:
-        fprintf(llogfile, "RSTAT: (");
-        offset += 2; /* ignored */
-        pprint_stat(pdu, 1, &offset, "stat");
-        break;
-    case P9_TWSTAT:
-        fprintf(llogfile, "TWSTAT: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        offset += 2; /* ignored */
-        pprint_stat(pdu, 0, &offset, ", stat");
-        break;
-    case P9_RWSTAT:
-        fprintf(llogfile, "RWSTAT: (");
-        break;
-    case P9_TXATTRWALK:
-        fprintf(llogfile, "TXATTRWALK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int32(pdu, 0, &offset, ", newfid");
-        pprint_str(pdu, 0, &offset, ", xattr name");
-        break;
-    case P9_RXATTRWALK:
-        fprintf(llogfile, "RXATTRWALK: (");
-        pprint_int64(pdu, 1, &offset, "xattrsize");
-    case P9_TXATTRCREATE:
-        fprintf(llogfile, "TXATTRCREATE: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, ", name");
-        pprint_int64(pdu, 0, &offset, ", xattrsize");
-        pprint_int32(pdu, 0, &offset, ", flags");
-        break;
-    case P9_RXATTRCREATE:
-        fprintf(llogfile, "RXATTRCREATE: (");
-        break;
-    case P9_TLOCK:
-        fprintf(llogfile, "TLOCK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int8(pdu, 0, &offset, ", type");
-        pprint_int32(pdu, 0, &offset, ", flags");
-        pprint_int64(pdu, 0, &offset, ", start");
-        pprint_int64(pdu, 0, &offset, ", length");
-        pprint_int32(pdu, 0, &offset, ", proc_id");
-        pprint_str(pdu, 0, &offset, ", client_id");
-        break;
-    case P9_RLOCK:
-        fprintf(llogfile, "RLOCK: (");
-        pprint_int8(pdu, 0, &offset, "status");
-        break;
-    case P9_TGETLOCK:
-        fprintf(llogfile, "TGETLOCK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_int8(pdu, 0, &offset, ", type");
-        pprint_int64(pdu, 0, &offset, ", start");
-        pprint_int64(pdu, 0, &offset, ", length");
-        pprint_int32(pdu, 0, &offset, ", proc_id");
-        pprint_str(pdu, 0, &offset, ", client_id");
-        break;
-    case P9_RGETLOCK:
-        fprintf(llogfile, "RGETLOCK: (");
-        pprint_int8(pdu, 0, &offset, "type");
-        pprint_int64(pdu, 0, &offset, ", start");
-        pprint_int64(pdu, 0, &offset, ", length");
-        pprint_int32(pdu, 0, &offset, ", proc_id");
-        pprint_str(pdu, 0, &offset, ", client_id");
-        break;
-    default:
-        fprintf(llogfile, "unknown(%d): (", pdu->id);
-        break;
-    }
-
-    fprintf(llogfile, ")\n");
-    /* Flush the log message out */
-    fflush(llogfile);
-}
diff --git a/hw/virtio-9p-debug.h b/hw/virtio-9p-debug.h
deleted file mode 100644 (file)
index d9a2491..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _QEMU_VIRTIO_9P_DEBUG_H
-#define _QEMU_VIRTIO_9P_DEBUG_H
-
-void pprint_pdu(V9fsPDU *pdu);
-
-#endif
diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c
deleted file mode 100644 (file)
index a8e7525..0000000
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- * Virtio 9p Posix callback
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-#include "virtio.h"
-#include "virtio-9p.h"
-#include "virtio-9p-xattr.h"
-#include <arpa/inet.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <attr/xattr.h>
-
-
-static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
-{
-    int err;
-    err =  lstat(rpath(fs_ctx, path), stbuf);
-    if (err) {
-        return err;
-    }
-    if (fs_ctx->fs_sm == SM_MAPPED) {
-        /* Actual credentials are part of extended attrs */
-        uid_t tmp_uid;
-        gid_t tmp_gid;
-        mode_t tmp_mode;
-        dev_t tmp_dev;
-        if (getxattr(rpath(fs_ctx, path), "user.virtfs.uid", &tmp_uid,
-                    sizeof(uid_t)) > 0) {
-            stbuf->st_uid = tmp_uid;
-        }
-        if (getxattr(rpath(fs_ctx, path), "user.virtfs.gid", &tmp_gid,
-                    sizeof(gid_t)) > 0) {
-            stbuf->st_gid = tmp_gid;
-        }
-        if (getxattr(rpath(fs_ctx, path), "user.virtfs.mode", &tmp_mode,
-                    sizeof(mode_t)) > 0) {
-            stbuf->st_mode = tmp_mode;
-        }
-        if (getxattr(rpath(fs_ctx, path), "user.virtfs.rdev", &tmp_dev,
-                        sizeof(dev_t)) > 0) {
-                stbuf->st_rdev = tmp_dev;
-        }
-    }
-    return err;
-}
-
-static int local_set_xattr(const char *path, FsCred *credp)
-{
-    int err;
-    if (credp->fc_uid != -1) {
-        err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
-                0);
-        if (err) {
-            return err;
-        }
-    }
-    if (credp->fc_gid != -1) {
-        err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
-                0);
-        if (err) {
-            return err;
-        }
-    }
-    if (credp->fc_mode != -1) {
-        err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
-                sizeof(mode_t), 0);
-        if (err) {
-            return err;
-        }
-    }
-    if (credp->fc_rdev != -1) {
-        err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
-                sizeof(dev_t), 0);
-        if (err) {
-            return err;
-        }
-    }
-    return 0;
-}
-
-static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
-        FsCred *credp)
-{
-    if (chmod(rpath(fs_ctx, path), credp->fc_mode & 07777) < 0) {
-        return -1;
-    }
-    if (lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
-        /*
-         * If we fail to change ownership and if we are
-         * using security model none. Ignore the error
-         */
-        if (fs_ctx->fs_sm != SM_NONE) {
-            return -1;
-        }
-    }
-    return 0;
-}
-
-static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
-        char *buf, size_t bufsz)
-{
-    ssize_t tsize = -1;
-    if (fs_ctx->fs_sm == SM_MAPPED) {
-        int fd;
-        fd = open(rpath(fs_ctx, path), O_RDONLY);
-        if (fd == -1) {
-            return -1;
-        }
-        do {
-            tsize = read(fd, (void *)buf, bufsz);
-        } while (tsize == -1 && errno == EINTR);
-        close(fd);
-        return tsize;
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
-        tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
-    }
-    return tsize;
-}
-
-static int local_close(FsContext *ctx, int fd)
-{
-    return close(fd);
-}
-
-static int local_closedir(FsContext *ctx, DIR *dir)
-{
-    return closedir(dir);
-}
-
-static int local_open(FsContext *ctx, const char *path, int flags)
-{
-    return open(rpath(ctx, path), flags);
-}
-
-static DIR *local_opendir(FsContext *ctx, const char *path)
-{
-    return opendir(rpath(ctx, path));
-}
-
-static void local_rewinddir(FsContext *ctx, DIR *dir)
-{
-    return rewinddir(dir);
-}
-
-static off_t local_telldir(FsContext *ctx, DIR *dir)
-{
-    return telldir(dir);
-}
-
-static struct dirent *local_readdir(FsContext *ctx, DIR *dir)
-{
-    return readdir(dir);
-}
-
-static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
-{
-    return seekdir(dir, off);
-}
-
-static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
-                            int iovcnt, off_t offset)
-{
-#ifdef CONFIG_PREADV
-    return preadv(fd, iov, iovcnt, offset);
-#else
-    int err = lseek(fd, offset, SEEK_SET);
-    if (err == -1) {
-        return err;
-    } else {
-        return readv(fd, iov, iovcnt);
-    }
-#endif
-}
-
-static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
-                            int iovcnt, off_t offset)
-{
-#ifdef CONFIG_PREADV
-    return pwritev(fd, iov, iovcnt, offset);
-#else
-    int err = lseek(fd, offset, SEEK_SET);
-    if (err == -1) {
-        return err;
-    } else {
-        return writev(fd, iov, iovcnt);
-    }
-#endif
-}
-
-static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
-{
-    if (fs_ctx->fs_sm == SM_MAPPED) {
-        return local_set_xattr(rpath(fs_ctx, path), credp);
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
-        return chmod(rpath(fs_ctx, path), credp->fc_mode);
-    }
-    return -1;
-}
-
-static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
-{
-    int err = -1;
-    int serrno = 0;
-
-    /* Determine the security model */
-    if (fs_ctx->fs_sm == SM_MAPPED) {
-        err = mknod(rpath(fs_ctx, path), SM_LOCAL_MODE_BITS|S_IFREG, 0);
-        if (err == -1) {
-            return err;
-        }
-        local_set_xattr(rpath(fs_ctx, path), credp);
-        if (err == -1) {
-            serrno = errno;
-            goto err_end;
-        }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
-        err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
-        if (err == -1) {
-            return err;
-        }
-        err = local_post_create_passthrough(fs_ctx, path, credp);
-        if (err == -1) {
-            serrno = errno;
-            goto err_end;
-        }
-    }
-    return err;
-
-err_end:
-    remove(rpath(fs_ctx, path));
-    errno = serrno;
-    return err;
-}
-
-static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
-{
-    int err = -1;
-    int serrno = 0;
-
-    /* Determine the security model */
-    if (fs_ctx->fs_sm == SM_MAPPED) {
-        err = mkdir(rpath(fs_ctx, path), SM_LOCAL_DIR_MODE_BITS);
-        if (err == -1) {
-            return err;
-        }
-        credp->fc_mode = credp->fc_mode|S_IFDIR;
-        err = local_set_xattr(rpath(fs_ctx, path), credp);
-        if (err == -1) {
-            serrno = errno;
-            goto err_end;
-        }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
-        err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
-        if (err == -1) {
-            return err;
-        }
-        err = local_post_create_passthrough(fs_ctx, path, credp);
-        if (err == -1) {
-            serrno = errno;
-            goto err_end;
-        }
-    }
-    return err;
-
-err_end:
-    remove(rpath(fs_ctx, path));
-    errno = serrno;
-    return err;
-}
-
-static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
-{
-    int err;
-    err = fstat(fd, stbuf);
-    if (err) {
-        return err;
-    }
-    if (fs_ctx->fs_sm == SM_MAPPED) {
-        /* Actual credentials are part of extended attrs */
-        uid_t tmp_uid;
-        gid_t tmp_gid;
-        mode_t tmp_mode;
-        dev_t tmp_dev;
-
-        if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
-            stbuf->st_uid = tmp_uid;
-        }
-        if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
-            stbuf->st_gid = tmp_gid;
-        }
-        if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
-            stbuf->st_mode = tmp_mode;
-        }
-        if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
-                stbuf->st_rdev = tmp_dev;
-        }
-    }
-    return err;
-}
-
-static int local_open2(FsContext *fs_ctx, const char *path, int flags,
-        FsCred *credp)
-{
-    int fd = -1;
-    int err = -1;
-    int serrno = 0;
-
-    /* Determine the security model */
-    if (fs_ctx->fs_sm == SM_MAPPED) {
-        fd = open(rpath(fs_ctx, path), flags, SM_LOCAL_MODE_BITS);
-        if (fd == -1) {
-            return fd;
-        }
-        credp->fc_mode = credp->fc_mode|S_IFREG;
-        /* Set cleint credentials in xattr */
-        err = local_set_xattr(rpath(fs_ctx, path), credp);
-        if (err == -1) {
-            serrno = errno;
-            goto err_end;
-        }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
-        fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
-        if (fd == -1) {
-            return fd;
-        }
-        err = local_post_create_passthrough(fs_ctx, path, credp);
-        if (err == -1) {
-            serrno = errno;
-            goto err_end;
-        }
-    }
-    return fd;
-
-err_end:
-    close(fd);
-    remove(rpath(fs_ctx, path));
-    errno = serrno;
-    return err;
-}
-
-
-static int local_symlink(FsContext *fs_ctx, const char *oldpath,
-        const char *newpath, FsCred *credp)
-{
-    int err = -1;
-    int serrno = 0;
-
-    /* Determine the security model */
-    if (fs_ctx->fs_sm == SM_MAPPED) {
-        int fd;
-        ssize_t oldpath_size, write_size;
-        fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
-                SM_LOCAL_MODE_BITS);
-        if (fd == -1) {
-            return fd;
-        }
-        /* Write the oldpath (target) to the file. */
-        oldpath_size = strlen(oldpath) + 1;
-        do {
-            write_size = write(fd, (void *)oldpath, oldpath_size);
-        } while (write_size == -1 && errno == EINTR);
-
-        if (write_size != oldpath_size) {
-            serrno = errno;
-            close(fd);
-            err = -1;
-            goto err_end;
-        }
-        close(fd);
-        /* Set cleint credentials in symlink's xattr */
-        credp->fc_mode = credp->fc_mode|S_IFLNK;
-        err = local_set_xattr(rpath(fs_ctx, newpath), credp);
-        if (err == -1) {
-            serrno = errno;
-            goto err_end;
-        }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
-        err = symlink(oldpath, rpath(fs_ctx, newpath));
-        if (err) {
-            return err;
-        }
-        err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
-        if (err == -1) {
-            /*
-             * If we fail to change ownership and if we are
-             * using security model none. Ignore the error
-             */
-            if (fs_ctx->fs_sm != SM_NONE) {
-                serrno = errno;
-                goto err_end;
-            } else
-                err = 0;
-        }
-    }
-    return err;
-
-err_end:
-    remove(rpath(fs_ctx, newpath));
-    errno = serrno;
-    return err;
-}
-
-static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
-{
-    char *tmp = qemu_strdup(rpath(ctx, oldpath));
-    int err, serrno = 0;
-
-    if (tmp == NULL) {
-        return -ENOMEM;
-    }
-
-    err = link(tmp, rpath(ctx, newpath));
-    if (err == -1) {
-        serrno = errno;
-    }
-
-    qemu_free(tmp);
-
-    if (err == -1) {
-        errno = serrno;
-    }
-
-    return err;
-}
-
-static int local_truncate(FsContext *ctx, const char *path, off_t size)
-{
-    return truncate(rpath(ctx, path), size);
-}
-
-static int local_rename(FsContext *ctx, const char *oldpath,
-                        const char *newpath)
-{
-    char *tmp;
-    int err;
-
-    tmp = qemu_strdup(rpath(ctx, oldpath));
-
-    err = rename(tmp, rpath(ctx, newpath));
-    if (err == -1) {
-        int serrno = errno;
-        qemu_free(tmp);
-        errno = serrno;
-    } else {
-        qemu_free(tmp);
-    }
-
-    return err;
-
-}
-
-static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
-{
-    if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
-            (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
-        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
-    } else if (fs_ctx->fs_sm == SM_MAPPED) {
-        return local_set_xattr(rpath(fs_ctx, path), credp);
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
-        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
-    }
-    return -1;
-}
-
-static int local_utimensat(FsContext *s, const char *path,
-                           const struct timespec *buf)
-{
-    return qemu_utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
-}
-
-static int local_remove(FsContext *ctx, const char *path)
-{
-    return remove(rpath(ctx, path));
-}
-
-static int local_fsync(FsContext *ctx, int fd, int datasync)
-{
-    if (datasync) {
-        return qemu_fdatasync(fd);
-    } else {
-        return fsync(fd);
-    }
-}
-
-static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
-{
-   return statfs(rpath(s, path), stbuf);
-}
-
-static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
-                               const char *name, void *value, size_t size)
-{
-    return v9fs_get_xattr(ctx, path, name, value, size);
-}
-
-static ssize_t local_llistxattr(FsContext *ctx, const char *path,
-                                void *value, size_t size)
-{
-    return v9fs_list_xattr(ctx, path, value, size);
-}
-
-static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
-                           void *value, size_t size, int flags)
-{
-    return v9fs_set_xattr(ctx, path, name, value, size, flags);
-}
-
-static int local_lremovexattr(FsContext *ctx,
-                              const char *path, const char *name)
-{
-    return v9fs_remove_xattr(ctx, path, name);
-}
-
-
-FileOperations local_ops = {
-    .lstat = local_lstat,
-    .readlink = local_readlink,
-    .close = local_close,
-    .closedir = local_closedir,
-    .open = local_open,
-    .opendir = local_opendir,
-    .rewinddir = local_rewinddir,
-    .telldir = local_telldir,
-    .readdir = local_readdir,
-    .seekdir = local_seekdir,
-    .preadv = local_preadv,
-    .pwritev = local_pwritev,
-    .chmod = local_chmod,
-    .mknod = local_mknod,
-    .mkdir = local_mkdir,
-    .fstat = local_fstat,
-    .open2 = local_open2,
-    .symlink = local_symlink,
-    .link = local_link,
-    .truncate = local_truncate,
-    .rename = local_rename,
-    .chown = local_chown,
-    .utimensat = local_utimensat,
-    .remove = local_remove,
-    .fsync = local_fsync,
-    .statfs = local_statfs,
-    .lgetxattr = local_lgetxattr,
-    .llistxattr = local_llistxattr,
-    .lsetxattr = local_lsetxattr,
-    .lremovexattr = local_lremovexattr,
-};
diff --git a/hw/virtio-9p-posix-acl.c b/hw/virtio-9p-posix-acl.c
deleted file mode 100644 (file)
index 3978d0c..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Virtio 9p system.posix* xattr callback
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include <sys/types.h>
-#include <attr/xattr.h>
-#include "virtio.h"
-#include "virtio-9p.h"
-#include "file-op-9p.h"
-#include "virtio-9p-xattr.h"
-
-#define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access"
-#define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default"
-#define ACL_ACCESS "system.posix_acl_access"
-#define ACL_DEFAULT "system.posix_acl_default"
-
-static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
-                                const char *name, void *value, size_t size)
-{
-    return lgetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size);
-}
-
-static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
-                                 char *name, void *value, size_t osize)
-{
-    ssize_t len = sizeof(ACL_ACCESS);
-
-    if (!value) {
-        return len;
-    }
-
-    if (osize < len) {
-        errno = ERANGE;
-        return -1;
-    }
-
-    strncpy(value, ACL_ACCESS, len);
-    return 0;
-}
-
-static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
-                            void *value, size_t size, int flags)
-{
-    return lsetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size, flags);
-}
-
-static int mp_pacl_removexattr(FsContext *ctx,
-                               const char *path, const char *name)
-{
-    int ret;
-    ret  = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS);
-    if (ret == -1 && errno == ENODATA) {
-        /*
-         * We don't get ENODATA error when trying to remote a
-         * posix acl that is not present. So don't throw the error
-         * even in case of mapped security model
-         */
-        errno = 0;
-        ret = 0;
-    }
-    return ret;
-}
-
-static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
-                                const char *name, void *value, size_t size)
-{
-    return lgetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size);
-}
-
-static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
-                                 char *name, void *value, size_t osize)
-{
-    ssize_t len = sizeof(ACL_DEFAULT);
-
-    if (!value) {
-        return len;
-    }
-
-    if (osize < len) {
-        errno = ERANGE;
-        return -1;
-    }
-
-    strncpy(value, ACL_DEFAULT, len);
-    return 0;
-}
-
-static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
-                            void *value, size_t size, int flags)
-{
-    return lsetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size, flags);
-}
-
-static int mp_dacl_removexattr(FsContext *ctx,
-                               const char *path, const char *name)
-{
-    return lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
-}
-
-
-XattrOperations mapped_pacl_xattr = {
-    .name = "system.posix_acl_access",
-    .getxattr = mp_pacl_getxattr,
-    .setxattr = mp_pacl_setxattr,
-    .listxattr = mp_pacl_listxattr,
-    .removexattr = mp_pacl_removexattr,
-};
-
-XattrOperations mapped_dacl_xattr = {
-    .name = "system.posix_acl_default",
-    .getxattr = mp_dacl_getxattr,
-    .setxattr = mp_dacl_setxattr,
-    .listxattr = mp_dacl_listxattr,
-    .removexattr = mp_dacl_removexattr,
-};
-
-XattrOperations passthrough_acl_xattr = {
-    .name = "system.posix_acl_",
-    .getxattr = pt_getxattr,
-    .setxattr = pt_setxattr,
-    .listxattr = pt_listxattr,
-    .removexattr = pt_removexattr,
-};
-
-XattrOperations none_acl_xattr = {
-    .name = "system.posix_acl_",
-    .getxattr = notsup_getxattr,
-    .setxattr = notsup_setxattr,
-    .listxattr = notsup_listxattr,
-    .removexattr = notsup_removexattr,
-};
diff --git a/hw/virtio-9p-xattr-user.c b/hw/virtio-9p-xattr-user.c
deleted file mode 100644 (file)
index faa02a1..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Virtio 9p user. xattr callback
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include <sys/types.h>
-#include "virtio.h"
-#include "virtio-9p.h"
-#include "file-op-9p.h"
-#include "virtio-9p-xattr.h"
-
-
-static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
-                                const char *name, void *value, size_t size)
-{
-    if (strncmp(name, "user.virtfs.", 12) == 0) {
-        /*
-         * Don't allow fetch of user.virtfs namesapce
-         * in case of mapped security
-         */
-        errno = ENOATTR;
-        return -1;
-    }
-    return lgetxattr(rpath(ctx, path), name, value, size);
-}
-
-static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
-                                 char *name, void *value, size_t size)
-{
-    int name_size = strlen(name) + 1;
-    if (strncmp(name, "user.virtfs.", 12) == 0) {
-
-        /*  check if it is a mapped posix acl */
-        if (strncmp(name, "user.virtfs.system.posix_acl_", 29) == 0) {
-            /* adjust the name and size */
-            name += 12;
-            name_size -= 12;
-        } else {
-            /*
-             * Don't allow fetch of user.virtfs namesapce
-             * in case of mapped security
-             */
-            return 0;
-        }
-    }
-    if (!value) {
-        return name_size;
-    }
-
-    if (size < name_size) {
-        errno = ERANGE;
-        return -1;
-    }
-
-    strncpy(value, name, name_size);
-    return name_size;
-}
-
-static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
-                            void *value, size_t size, int flags)
-{
-    if (strncmp(name, "user.virtfs.", 12) == 0) {
-        /*
-         * Don't allow fetch of user.virtfs namesapce
-         * in case of mapped security
-         */
-        errno = EACCES;
-        return -1;
-    }
-    return lsetxattr(rpath(ctx, path), name, value, size, flags);
-}
-
-static int mp_user_removexattr(FsContext *ctx,
-                               const char *path, const char *name)
-{
-    if (strncmp(name, "user.virtfs.", 12) == 0) {
-        /*
-         * Don't allow fetch of user.virtfs namesapce
-         * in case of mapped security
-         */
-        errno = EACCES;
-        return -1;
-    }
-    return lremovexattr(rpath(ctx, path), name);
-}
-
-XattrOperations mapped_user_xattr = {
-    .name = "user.",
-    .getxattr = mp_user_getxattr,
-    .setxattr = mp_user_setxattr,
-    .listxattr = mp_user_listxattr,
-    .removexattr = mp_user_removexattr,
-};
-
-XattrOperations passthrough_user_xattr = {
-    .name = "user.",
-    .getxattr = pt_getxattr,
-    .setxattr = pt_setxattr,
-    .listxattr = pt_listxattr,
-    .removexattr = pt_removexattr,
-};
diff --git a/hw/virtio-9p-xattr.c b/hw/virtio-9p-xattr.c
deleted file mode 100644 (file)
index 1aab081..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Virtio 9p  xattr callback
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "virtio.h"
-#include "virtio-9p.h"
-#include "file-op-9p.h"
-#include "virtio-9p-xattr.h"
-
-
-static XattrOperations *get_xattr_operations(XattrOperations **h,
-                                             const char *name)
-{
-    XattrOperations *xops;
-    for (xops = *(h)++; xops != NULL; xops = *(h)++) {
-        if (!strncmp(name, xops->name, strlen(xops->name))) {
-            return xops;
-        }
-    }
-    return NULL;
-}
-
-ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
-                       const char *name, void *value, size_t size)
-{
-    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
-    if (xops) {
-        return xops->getxattr(ctx, path, name, value, size);
-    }
-    errno = -EOPNOTSUPP;
-    return -1;
-}
-
-ssize_t pt_listxattr(FsContext *ctx, const char *path,
-                     char *name, void *value, size_t size)
-{
-    int name_size = strlen(name) + 1;
-    if (!value) {
-        return name_size;
-    }
-
-    if (size < name_size) {
-        errno = ERANGE;
-        return -1;
-    }
-
-    strncpy(value, name, name_size);
-    return name_size;
-}
-
-
-/*
- * Get the list and pass to each layer to find out whether
- * to send the data or not
- */
-ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
-                        void *value, size_t vsize)
-{
-    ssize_t size = 0;
-    void *ovalue = value;
-    XattrOperations *xops;
-    char *orig_value, *orig_value_start;
-    ssize_t xattr_len, parsed_len = 0, attr_len;
-
-    /* Get the actual len */
-    xattr_len = llistxattr(rpath(ctx, path), value, 0);
-    if (xattr_len <= 0) {
-        return xattr_len;
-    }
-
-    /* Now fetch the xattr and find the actual size */
-    orig_value = qemu_malloc(xattr_len);
-    xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
-
-    /* store the orig pointer */
-    orig_value_start = orig_value;
-    while (xattr_len > parsed_len) {
-        xops = get_xattr_operations(ctx->xops, orig_value);
-        if (!xops) {
-            goto next_entry;
-        }
-
-        if (!value) {
-            size += xops->listxattr(ctx, path, orig_value, value, vsize);
-        } else {
-            size = xops->listxattr(ctx, path, orig_value, value, vsize);
-            if (size < 0) {
-                goto err_out;
-            }
-            value += size;
-            vsize -= size;
-        }
-next_entry:
-        /* Got the next entry */
-        attr_len = strlen(orig_value) + 1;
-        parsed_len += attr_len;
-        orig_value += attr_len;
-    }
-    if (value) {
-        size = value - ovalue;
-    }
-
-err_out:
-    qemu_free(orig_value_start);
-    return size;
-}
-
-int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
-                   void *value, size_t size, int flags)
-{
-    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
-    if (xops) {
-        return xops->setxattr(ctx, path, name, value, size, flags);
-    }
-    errno = -EOPNOTSUPP;
-    return -1;
-
-}
-
-int v9fs_remove_xattr(FsContext *ctx,
-                      const char *path, const char *name)
-{
-    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
-    if (xops) {
-        return xops->removexattr(ctx, path, name);
-    }
-    errno = -EOPNOTSUPP;
-    return -1;
-
-}
-
-XattrOperations *mapped_xattr_ops[] = {
-    &mapped_user_xattr,
-    &mapped_pacl_xattr,
-    &mapped_dacl_xattr,
-    NULL,
-};
-
-XattrOperations *passthrough_xattr_ops[] = {
-    &passthrough_user_xattr,
-    &passthrough_acl_xattr,
-    NULL,
-};
-
-/* for .user none model should be same as passthrough */
-XattrOperations *none_xattr_ops[] = {
-    &passthrough_user_xattr,
-    &none_acl_xattr,
-    NULL,
-};
diff --git a/hw/virtio-9p-xattr.h b/hw/virtio-9p-xattr.h
deleted file mode 100644 (file)
index 2bbae2d..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Virtio 9p
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-#ifndef _QEMU_VIRTIO_9P_XATTR_H
-#define _QEMU_VIRTIO_9P_XATTR_H
-
-#include <attr/xattr.h>
-
-typedef struct xattr_operations
-{
-    const char *name;
-    ssize_t (*getxattr)(FsContext *ctx, const char *path,
-                        const char *name, void *value, size_t size);
-    ssize_t (*listxattr)(FsContext *ctx, const char *path,
-                         char *name, void *value, size_t size);
-    int (*setxattr)(FsContext *ctx, const char *path, const char *name,
-                    void *value, size_t size, int flags);
-    int (*removexattr)(FsContext *ctx,
-                       const char *path, const char *name);
-} XattrOperations;
-
-
-extern XattrOperations mapped_user_xattr;
-extern XattrOperations passthrough_user_xattr;
-
-extern XattrOperations mapped_pacl_xattr;
-extern XattrOperations mapped_dacl_xattr;
-extern XattrOperations passthrough_acl_xattr;
-extern XattrOperations none_acl_xattr;
-
-extern XattrOperations *mapped_xattr_ops[];
-extern XattrOperations *passthrough_xattr_ops[];
-extern XattrOperations *none_xattr_ops[];
-
-ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, const char *name,
-                       void *value, size_t size);
-ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value,
-                        size_t vsize);
-int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
-                          void *value, size_t size, int flags);
-int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
-ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
-                     size_t size);
-
-static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
-                                  const char *name, void *value, size_t size)
-{
-    return lgetxattr(rpath(ctx, path), name, value, size);
-}
-
-static inline int pt_setxattr(FsContext *ctx, const char *path,
-                              const char *name, void *value,
-                              size_t size, int flags)
-{
-    return lsetxattr(rpath(ctx, path), name, value, size, flags);
-}
-
-static inline int pt_removexattr(FsContext *ctx,
-                                 const char *path, const char *name)
-{
-    return lremovexattr(rpath(ctx, path), name);
-}
-
-static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
-                                      const char *name, void *value,
-                                      size_t size)
-{
-    errno = ENOTSUP;
-    return -1;
-}
-
-static inline int notsup_setxattr(FsContext *ctx, const char *path,
-                                  const char *name, void *value,
-                                  size_t size, int flags)
-{
-    errno = ENOTSUP;
-    return -1;
-}
-
-static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
-                                       char *name, void *value, size_t size)
-{
-    return 0;
-}
-
-static inline int notsup_removexattr(FsContext *ctx,
-                                     const char *path, const char *name)
-{
-    errno = ENOTSUP;
-    return -1;
-}
-
-#endif
diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c
deleted file mode 100644 (file)
index 7c59988..0000000
+++ /dev/null
@@ -1,3744 +0,0 @@
-/*
- * Virtio 9p backend
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "virtio.h"
-#include "pc.h"
-#include "qemu_socket.h"
-#include "virtio-9p.h"
-#include "fsdev/qemu-fsdev.h"
-#include "virtio-9p-debug.h"
-#include "virtio-9p-xattr.h"
-
-int debug_9p_pdu;
-
-enum {
-    Oread   = 0x00,
-    Owrite  = 0x01,
-    Ordwr   = 0x02,
-    Oexec   = 0x03,
-    Oexcl   = 0x04,
-    Otrunc  = 0x10,
-    Orexec  = 0x20,
-    Orclose = 0x40,
-    Oappend = 0x80,
-};
-
-static int omode_to_uflags(int8_t mode)
-{
-    int ret = 0;
-
-    switch (mode & 3) {
-    case Oread:
-        ret = O_RDONLY;
-        break;
-    case Ordwr:
-        ret = O_RDWR;
-        break;
-    case Owrite:
-        ret = O_WRONLY;
-        break;
-    case Oexec:
-        ret = O_RDONLY;
-        break;
-    }
-
-    if (mode & Otrunc) {
-        ret |= O_TRUNC;
-    }
-
-    if (mode & Oappend) {
-        ret |= O_APPEND;
-    }
-
-    if (mode & Oexcl) {
-        ret |= O_EXCL;
-    }
-
-    return ret;
-}
-
-void cred_init(FsCred *credp)
-{
-    credp->fc_uid = -1;
-    credp->fc_gid = -1;
-    credp->fc_mode = -1;
-    credp->fc_rdev = -1;
-}
-
-static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
-{
-    return s->ops->lstat(&s->ctx, path->data, stbuf);
-}
-
-static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
-{
-    ssize_t len;
-
-    buf->data = qemu_malloc(1024);
-
-    len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
-    if (len > -1) {
-        buf->size = len;
-        buf->data[len] = 0;
-    }
-
-    return len;
-}
-
-static int v9fs_do_close(V9fsState *s, int fd)
-{
-    return s->ops->close(&s->ctx, fd);
-}
-
-static int v9fs_do_closedir(V9fsState *s, DIR *dir)
-{
-    return s->ops->closedir(&s->ctx, dir);
-}
-
-static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
-{
-    return s->ops->open(&s->ctx, path->data, flags);
-}
-
-static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
-{
-    return s->ops->opendir(&s->ctx, path->data);
-}
-
-static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
-{
-    return s->ops->rewinddir(&s->ctx, dir);
-}
-
-static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
-{
-    return s->ops->telldir(&s->ctx, dir);
-}
-
-static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
-{
-    return s->ops->readdir(&s->ctx, dir);
-}
-
-static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
-{
-    return s->ops->seekdir(&s->ctx, dir, off);
-}
-
-static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
-                            int iovcnt, int64_t offset)
-{
-    return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
-}
-
-static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
-                       int iovcnt, int64_t offset)
-{
-    return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
-}
-
-static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
-{
-    FsCred cred;
-    cred_init(&cred);
-    cred.fc_mode = mode;
-    return s->ops->chmod(&s->ctx, path->data, &cred);
-}
-
-static int v9fs_do_mknod(V9fsState *s, char *name,
-        mode_t mode, dev_t dev, uid_t uid, gid_t gid)
-{
-    FsCred cred;
-    cred_init(&cred);
-    cred.fc_uid = uid;
-    cred.fc_gid = gid;
-    cred.fc_mode = mode;
-    cred.fc_rdev = dev;
-    return s->ops->mknod(&s->ctx, name, &cred);
-}
-
-static int v9fs_do_mkdir(V9fsState *s, char *name, mode_t mode,
-                uid_t uid, gid_t gid)
-{
-    FsCred cred;
-
-    cred_init(&cred);
-    cred.fc_uid = uid;
-    cred.fc_gid = gid;
-    cred.fc_mode = mode;
-
-    return s->ops->mkdir(&s->ctx, name, &cred);
-}
-
-static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
-{
-    return s->ops->fstat(&s->ctx, fd, stbuf);
-}
-
-static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
-        int flags, int mode)
-{
-    FsCred cred;
-
-    cred_init(&cred);
-    cred.fc_uid = uid;
-    cred.fc_gid = gid;
-    cred.fc_mode = mode & 07777;
-    flags = flags;
-
-    return s->ops->open2(&s->ctx, fullname, flags, &cred);
-}
-
-static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
-        const char *oldpath, const char *newpath, gid_t gid)
-{
-    FsCred cred;
-    cred_init(&cred);
-    cred.fc_uid = fidp->uid;
-    cred.fc_gid = gid;
-    cred.fc_mode = 0777;
-
-    return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
-}
-
-static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
-{
-    return s->ops->link(&s->ctx, oldpath->data, newpath->data);
-}
-
-static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
-{
-    return s->ops->truncate(&s->ctx, path->data, size);
-}
-
-static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
-                            V9fsString *newpath)
-{
-    return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
-}
-
-static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
-{
-    FsCred cred;
-    cred_init(&cred);
-    cred.fc_uid = uid;
-    cred.fc_gid = gid;
-
-    return s->ops->chown(&s->ctx, path->data, &cred);
-}
-
-static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
-                                           const struct timespec times[2])
-{
-    return s->ops->utimensat(&s->ctx, path->data, times);
-}
-
-static int v9fs_do_remove(V9fsState *s, V9fsString *path)
-{
-    return s->ops->remove(&s->ctx, path->data);
-}
-
-static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
-{
-    return s->ops->fsync(&s->ctx, fd, datasync);
-}
-
-static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
-{
-    return s->ops->statfs(&s->ctx, path->data, stbuf);
-}
-
-static ssize_t v9fs_do_lgetxattr(V9fsState *s, V9fsString *path,
-                             V9fsString *xattr_name,
-                             void *value, size_t size)
-{
-    return s->ops->lgetxattr(&s->ctx, path->data,
-                             xattr_name->data, value, size);
-}
-
-static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
-                              void *value, size_t size)
-{
-    return s->ops->llistxattr(&s->ctx, path->data,
-                              value, size);
-}
-
-static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
-                             V9fsString *xattr_name,
-                             void *value, size_t size, int flags)
-{
-    return s->ops->lsetxattr(&s->ctx, path->data,
-                             xattr_name->data, value, size, flags);
-}
-
-static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
-                                V9fsString *xattr_name)
-{
-    return s->ops->lremovexattr(&s->ctx, path->data,
-                                xattr_name->data);
-}
-
-
-static void v9fs_string_init(V9fsString *str)
-{
-    str->data = NULL;
-    str->size = 0;
-}
-
-static void v9fs_string_free(V9fsString *str)
-{
-    qemu_free(str->data);
-    str->data = NULL;
-    str->size = 0;
-}
-
-static void v9fs_string_null(V9fsString *str)
-{
-    v9fs_string_free(str);
-}
-
-static int number_to_string(void *arg, char type)
-{
-    unsigned int ret = 0;
-
-    switch (type) {
-    case 'u': {
-        unsigned int num = *(unsigned int *)arg;
-
-        do {
-            ret++;
-            num = num/10;
-        } while (num);
-        break;
-    }
-    case 'U': {
-        unsigned long num = *(unsigned long *)arg;
-        do {
-            ret++;
-            num = num/10;
-        } while (num);
-        break;
-    }
-    default:
-        printf("Number_to_string: Unknown number format\n");
-        return -1;
-    }
-
-    return ret;
-}
-
-static int GCC_FMT_ATTR(2, 0)
-v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
-{
-    va_list ap2;
-    char *iter = (char *)fmt;
-    int len = 0;
-    int nr_args = 0;
-    char *arg_char_ptr;
-    unsigned int arg_uint;
-    unsigned long arg_ulong;
-
-    /* Find the number of %'s that denotes an argument */
-    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
-        nr_args++;
-        iter++;
-    }
-
-    len = strlen(fmt) - 2*nr_args;
-
-    if (!nr_args) {
-        goto alloc_print;
-    }
-
-    va_copy(ap2, ap);
-
-    iter = (char *)fmt;
-
-    /* Now parse the format string */
-    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
-        iter++;
-        switch (*iter) {
-        case 'u':
-            arg_uint = va_arg(ap2, unsigned int);
-            len += number_to_string((void *)&arg_uint, 'u');
-            break;
-        case 'l':
-            if (*++iter == 'u') {
-                arg_ulong = va_arg(ap2, unsigned long);
-                len += number_to_string((void *)&arg_ulong, 'U');
-            } else {
-                return -1;
-            }
-            break;
-        case 's':
-            arg_char_ptr = va_arg(ap2, char *);
-            len += strlen(arg_char_ptr);
-            break;
-        case 'c':
-            len += 1;
-            break;
-        default:
-            fprintf(stderr,
-                   "v9fs_string_alloc_printf:Incorrect format %c", *iter);
-            return -1;
-        }
-        iter++;
-    }
-
-alloc_print:
-    *strp = qemu_malloc((len + 1) * sizeof(**strp));
-
-    return vsprintf(*strp, fmt, ap);
-}
-
-static void GCC_FMT_ATTR(2, 3)
-v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
-{
-    va_list ap;
-    int err;
-
-    v9fs_string_free(str);
-
-    va_start(ap, fmt);
-    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
-    BUG_ON(err == -1);
-    va_end(ap);
-
-    str->size = err;
-}
-
-static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
-{
-    v9fs_string_free(lhs);
-    v9fs_string_sprintf(lhs, "%s", rhs->data);
-}
-
-static size_t v9fs_string_size(V9fsString *str)
-{
-    return str->size;
-}
-
-static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
-{
-    V9fsFidState *f;
-
-    for (f = s->fid_list; f; f = f->next) {
-        if (f->fid == fid) {
-            return f;
-        }
-    }
-
-    return NULL;
-}
-
-static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
-{
-    V9fsFidState *f;
-
-    f = lookup_fid(s, fid);
-    if (f) {
-        return NULL;
-    }
-
-    f = qemu_mallocz(sizeof(V9fsFidState));
-
-    f->fid = fid;
-    f->fid_type = P9_FID_NONE;
-
-    f->next = s->fid_list;
-    s->fid_list = f;
-
-    return f;
-}
-
-static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
-{
-    int retval = 0;
-
-    if (fidp->fs.xattr.copied_len == -1) {
-        /* getxattr/listxattr fid */
-        goto free_value;
-    }
-    /*
-     * if this is fid for setxattr. clunk should
-     * result in setxattr localcall
-     */
-    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
-        /* clunk after partial write */
-        retval = -EINVAL;
-        goto free_out;
-    }
-    if (fidp->fs.xattr.len) {
-        retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
-                                   fidp->fs.xattr.value,
-                                   fidp->fs.xattr.len,
-                                   fidp->fs.xattr.flags);
-    } else {
-        retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
-    }
-free_out:
-    v9fs_string_free(&fidp->fs.xattr.name);
-free_value:
-    if (fidp->fs.xattr.value) {
-        qemu_free(fidp->fs.xattr.value);
-    }
-    return retval;
-}
-
-static int free_fid(V9fsState *s, int32_t fid)
-{
-    int retval = 0;
-    V9fsFidState **fidpp, *fidp;
-
-    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
-        if ((*fidpp)->fid == fid) {
-            break;
-        }
-    }
-
-    if (*fidpp == NULL) {
-        return -ENOENT;
-    }
-
-    fidp = *fidpp;
-    *fidpp = fidp->next;
-
-    if (fidp->fid_type == P9_FID_FILE) {
-        v9fs_do_close(s, fidp->fs.fd);
-    } else if (fidp->fid_type == P9_FID_DIR) {
-        v9fs_do_closedir(s, fidp->fs.dir);
-    } else if (fidp->fid_type == P9_FID_XATTR) {
-        retval = v9fs_xattr_fid_clunk(s, fidp);
-    }
-    v9fs_string_free(&fidp->path);
-    qemu_free(fidp);
-
-    return retval;
-}
-
-#define P9_QID_TYPE_DIR         0x80
-#define P9_QID_TYPE_SYMLINK     0x02
-
-#define P9_STAT_MODE_DIR        0x80000000
-#define P9_STAT_MODE_APPEND     0x40000000
-#define P9_STAT_MODE_EXCL       0x20000000
-#define P9_STAT_MODE_MOUNT      0x10000000
-#define P9_STAT_MODE_AUTH       0x08000000
-#define P9_STAT_MODE_TMP        0x04000000
-#define P9_STAT_MODE_SYMLINK    0x02000000
-#define P9_STAT_MODE_LINK       0x01000000
-#define P9_STAT_MODE_DEVICE     0x00800000
-#define P9_STAT_MODE_NAMED_PIPE 0x00200000
-#define P9_STAT_MODE_SOCKET     0x00100000
-#define P9_STAT_MODE_SETUID     0x00080000
-#define P9_STAT_MODE_SETGID     0x00040000
-#define P9_STAT_MODE_SETVTX     0x00010000
-
-#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
-                                P9_STAT_MODE_SYMLINK |      \
-                                P9_STAT_MODE_LINK |         \
-                                P9_STAT_MODE_DEVICE |       \
-                                P9_STAT_MODE_NAMED_PIPE |   \
-                                P9_STAT_MODE_SOCKET)
-
-/* This is the algorithm from ufs in spfs */
-static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
-{
-    size_t size;
-
-    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
-    memcpy(&qidp->path, &stbuf->st_ino, size);
-    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
-    qidp->type = 0;
-    if (S_ISDIR(stbuf->st_mode)) {
-        qidp->type |= P9_QID_TYPE_DIR;
-    }
-    if (S_ISLNK(stbuf->st_mode)) {
-        qidp->type |= P9_QID_TYPE_SYMLINK;
-    }
-}
-
-static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
-{
-    struct stat stbuf;
-    int err;
-
-    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
-    if (err) {
-        return err;
-    }
-
-    stat_to_qid(&stbuf, qidp);
-    return 0;
-}
-
-static V9fsPDU *alloc_pdu(V9fsState *s)
-{
-    V9fsPDU *pdu = NULL;
-
-    if (!QLIST_EMPTY(&s->free_list)) {
-       pdu = QLIST_FIRST(&s->free_list);
-       QLIST_REMOVE(pdu, next);
-    }
-    return pdu;
-}
-
-static void free_pdu(V9fsState *s, V9fsPDU *pdu)
-{
-    if (pdu) {
-       QLIST_INSERT_HEAD(&s->free_list, pdu, next);
-    }
-}
-
-size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
-                        size_t offset, size_t size, int pack)
-{
-    int i = 0;
-    size_t copied = 0;
-
-    for (i = 0; size && i < sg_count; i++) {
-        size_t len;
-        if (offset >= sg[i].iov_len) {
-            /* skip this sg */
-            offset -= sg[i].iov_len;
-            continue;
-        } else {
-            len = MIN(sg[i].iov_len - offset, size);
-            if (pack) {
-                memcpy(sg[i].iov_base + offset, addr, len);
-            } else {
-                memcpy(addr, sg[i].iov_base + offset, len);
-            }
-            size -= len;
-            copied += len;
-            addr += len;
-            if (size) {
-                offset = 0;
-                continue;
-            }
-        }
-    }
-
-    return copied;
-}
-
-static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
-{
-    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
-                         offset, size, 0);
-}
-
-static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
-                        size_t size)
-{
-    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
-                             offset, size, 1);
-}
-
-static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
-{
-    size_t pos = 0;
-    int i, j;
-    struct iovec *src_sg;
-    unsigned int num;
-
-    if (rx) {
-        src_sg = pdu->elem.in_sg;
-        num = pdu->elem.in_num;
-    } else {
-        src_sg = pdu->elem.out_sg;
-        num = pdu->elem.out_num;
-    }
-
-    j = 0;
-    for (i = 0; i < num; i++) {
-        if (offset <= pos) {
-            sg[j].iov_base = src_sg[i].iov_base;
-            sg[j].iov_len = src_sg[i].iov_len;
-            j++;
-        } else if (offset < (src_sg[i].iov_len + pos)) {
-            sg[j].iov_base = src_sg[i].iov_base;
-            sg[j].iov_len = src_sg[i].iov_len;
-            sg[j].iov_base += (offset - pos);
-            sg[j].iov_len -= (offset - pos);
-            j++;
-        }
-        pos += src_sg[i].iov_len;
-    }
-
-    return j;
-}
-
-static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
-{
-    size_t old_offset = offset;
-    va_list ap;
-    int i;
-
-    va_start(ap, fmt);
-    for (i = 0; fmt[i]; i++) {
-        switch (fmt[i]) {
-        case 'b': {
-            uint8_t *valp = va_arg(ap, uint8_t *);
-            offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
-            break;
-        }
-        case 'w': {
-            uint16_t val, *valp;
-            valp = va_arg(ap, uint16_t *);
-            val = le16_to_cpupu(valp);
-            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
-            *valp = val;
-            break;
-        }
-        case 'd': {
-            uint32_t val, *valp;
-            valp = va_arg(ap, uint32_t *);
-            val = le32_to_cpupu(valp);
-            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
-            *valp = val;
-            break;
-        }
-        case 'q': {
-            uint64_t val, *valp;
-            valp = va_arg(ap, uint64_t *);
-            val = le64_to_cpup(valp);
-            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
-            *valp = val;
-            break;
-        }
-        case 'v': {
-            struct iovec *iov = va_arg(ap, struct iovec *);
-            int *iovcnt = va_arg(ap, int *);
-            *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
-            break;
-        }
-        case 's': {
-            V9fsString *str = va_arg(ap, V9fsString *);
-            offset += pdu_unmarshal(pdu, offset, "w", &str->size);
-            /* FIXME: sanity check str->size */
-            str->data = qemu_malloc(str->size + 1);
-            offset += pdu_unpack(str->data, pdu, offset, str->size);
-            str->data[str->size] = 0;
-            break;
-        }
-        case 'Q': {
-            V9fsQID *qidp = va_arg(ap, V9fsQID *);
-            offset += pdu_unmarshal(pdu, offset, "bdq",
-                        &qidp->type, &qidp->version, &qidp->path);
-            break;
-        }
-        case 'S': {
-            V9fsStat *statp = va_arg(ap, V9fsStat *);
-            offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
-                        &statp->size, &statp->type, &statp->dev,
-                        &statp->qid, &statp->mode, &statp->atime,
-                        &statp->mtime, &statp->length,
-                        &statp->name, &statp->uid, &statp->gid,
-                        &statp->muid, &statp->extension,
-                        &statp->n_uid, &statp->n_gid,
-                        &statp->n_muid);
-            break;
-        }
-        case 'I': {
-            V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
-            offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
-                        &iattr->valid, &iattr->mode,
-                        &iattr->uid, &iattr->gid, &iattr->size,
-                        &iattr->atime_sec, &iattr->atime_nsec,
-                        &iattr->mtime_sec, &iattr->mtime_nsec);
-            break;
-        }
-        default:
-            break;
-        }
-    }
-
-    va_end(ap);
-
-    return offset - old_offset;
-}
-
-static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
-{
-    size_t old_offset = offset;
-    va_list ap;
-    int i;
-
-    va_start(ap, fmt);
-    for (i = 0; fmt[i]; i++) {
-        switch (fmt[i]) {
-        case 'b': {
-            uint8_t val = va_arg(ap, int);
-            offset += pdu_pack(pdu, offset, &val, sizeof(val));
-            break;
-        }
-        case 'w': {
-            uint16_t val;
-            cpu_to_le16w(&val, va_arg(ap, int));
-            offset += pdu_pack(pdu, offset, &val, sizeof(val));
-            break;
-        }
-        case 'd': {
-            uint32_t val;
-            cpu_to_le32w(&val, va_arg(ap, uint32_t));
-            offset += pdu_pack(pdu, offset, &val, sizeof(val));
-            break;
-        }
-        case 'q': {
-            uint64_t val;
-            cpu_to_le64w(&val, va_arg(ap, uint64_t));
-            offset += pdu_pack(pdu, offset, &val, sizeof(val));
-            break;
-        }
-        case 'v': {
-            struct iovec *iov = va_arg(ap, struct iovec *);
-            int *iovcnt = va_arg(ap, int *);
-            *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
-            break;
-        }
-        case 's': {
-            V9fsString *str = va_arg(ap, V9fsString *);
-            offset += pdu_marshal(pdu, offset, "w", str->size);
-            offset += pdu_pack(pdu, offset, str->data, str->size);
-            break;
-        }
-        case 'Q': {
-            V9fsQID *qidp = va_arg(ap, V9fsQID *);
-            offset += pdu_marshal(pdu, offset, "bdq",
-                        qidp->type, qidp->version, qidp->path);
-            break;
-        }
-        case 'S': {
-            V9fsStat *statp = va_arg(ap, V9fsStat *);
-            offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
-                        statp->size, statp->type, statp->dev,
-                        &statp->qid, statp->mode, statp->atime,
-                        statp->mtime, statp->length, &statp->name,
-                        &statp->uid, &statp->gid, &statp->muid,
-                        &statp->extension, statp->n_uid,
-                        statp->n_gid, statp->n_muid);
-            break;
-        }
-        case 'A': {
-            V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
-            offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
-                        statp->st_result_mask,
-                        &statp->qid, statp->st_mode,
-                        statp->st_uid, statp->st_gid,
-                        statp->st_nlink, statp->st_rdev,
-                        statp->st_size, statp->st_blksize, statp->st_blocks,
-                        statp->st_atime_sec, statp->st_atime_nsec,
-                        statp->st_mtime_sec, statp->st_mtime_nsec,
-                        statp->st_ctime_sec, statp->st_ctime_nsec,
-                        statp->st_btime_sec, statp->st_btime_nsec,
-                        statp->st_gen, statp->st_data_version);
-            break;
-        }
-        default:
-            break;
-        }
-    }
-    va_end(ap);
-
-    return offset - old_offset;
-}
-
-static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
-{
-    int8_t id = pdu->id + 1; /* Response */
-
-    if (len < 0) {
-        int err = -len;
-        len = 7;
-
-        if (s->proto_version != V9FS_PROTO_2000L) {
-            V9fsString str;
-
-            str.data = strerror(err);
-            str.size = strlen(str.data);
-
-            len += pdu_marshal(pdu, len, "s", &str);
-            id = P9_RERROR;
-        }
-
-        len += pdu_marshal(pdu, len, "d", err);
-
-        if (s->proto_version == V9FS_PROTO_2000L) {
-            id = P9_RLERROR;
-        }
-    }
-
-    /* fill out the header */
-    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
-
-    /* keep these in sync */
-    pdu->size = len;
-    pdu->id = id;
-
-    /* push onto queue and notify */
-    virtqueue_push(s->vq, &pdu->elem, len);
-
-    /* FIXME: we should batch these completions */
-    virtio_notify(&s->vdev, s->vq);
-
-    free_pdu(s, pdu);
-}
-
-static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
-{
-    mode_t ret;
-
-    ret = mode & 0777;
-    if (mode & P9_STAT_MODE_DIR) {
-        ret |= S_IFDIR;
-    }
-
-    if (mode & P9_STAT_MODE_SYMLINK) {
-        ret |= S_IFLNK;
-    }
-    if (mode & P9_STAT_MODE_SOCKET) {
-        ret |= S_IFSOCK;
-    }
-    if (mode & P9_STAT_MODE_NAMED_PIPE) {
-        ret |= S_IFIFO;
-    }
-    if (mode & P9_STAT_MODE_DEVICE) {
-        if (extension && extension->data[0] == 'c') {
-            ret |= S_IFCHR;
-        } else {
-            ret |= S_IFBLK;
-        }
-    }
-
-    if (!(ret&~0777)) {
-        ret |= S_IFREG;
-    }
-
-    if (mode & P9_STAT_MODE_SETUID) {
-        ret |= S_ISUID;
-    }
-    if (mode & P9_STAT_MODE_SETGID) {
-        ret |= S_ISGID;
-    }
-    if (mode & P9_STAT_MODE_SETVTX) {
-        ret |= S_ISVTX;
-    }
-
-    return ret;
-}
-
-static int donttouch_stat(V9fsStat *stat)
-{
-    if (stat->type == -1 &&
-        stat->dev == -1 &&
-        stat->qid.type == -1 &&
-        stat->qid.version == -1 &&
-        stat->qid.path == -1 &&
-        stat->mode == -1 &&
-        stat->atime == -1 &&
-        stat->mtime == -1 &&
-        stat->length == -1 &&
-        !stat->name.size &&
-        !stat->uid.size &&
-        !stat->gid.size &&
-        !stat->muid.size &&
-        stat->n_uid == -1 &&
-        stat->n_gid == -1 &&
-        stat->n_muid == -1) {
-        return 1;
-    }
-
-    return 0;
-}
-
-static void v9fs_stat_free(V9fsStat *stat)
-{
-    v9fs_string_free(&stat->name);
-    v9fs_string_free(&stat->uid);
-    v9fs_string_free(&stat->gid);
-    v9fs_string_free(&stat->muid);
-    v9fs_string_free(&stat->extension);
-}
-
-static uint32_t stat_to_v9mode(const struct stat *stbuf)
-{
-    uint32_t mode;
-
-    mode = stbuf->st_mode & 0777;
-    if (S_ISDIR(stbuf->st_mode)) {
-        mode |= P9_STAT_MODE_DIR;
-    }
-
-    if (S_ISLNK(stbuf->st_mode)) {
-        mode |= P9_STAT_MODE_SYMLINK;
-    }
-
-    if (S_ISSOCK(stbuf->st_mode)) {
-        mode |= P9_STAT_MODE_SOCKET;
-    }
-
-    if (S_ISFIFO(stbuf->st_mode)) {
-        mode |= P9_STAT_MODE_NAMED_PIPE;
-    }
-
-    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
-        mode |= P9_STAT_MODE_DEVICE;
-    }
-
-    if (stbuf->st_mode & S_ISUID) {
-        mode |= P9_STAT_MODE_SETUID;
-    }
-
-    if (stbuf->st_mode & S_ISGID) {
-        mode |= P9_STAT_MODE_SETGID;
-    }
-
-    if (stbuf->st_mode & S_ISVTX) {
-        mode |= P9_STAT_MODE_SETVTX;
-    }
-
-    return mode;
-}
-
-static int stat_to_v9stat(V9fsState *s, V9fsString *name,
-                            const struct stat *stbuf,
-                            V9fsStat *v9stat)
-{
-    int err;
-    const char *str;
-
-    memset(v9stat, 0, sizeof(*v9stat));
-
-    stat_to_qid(stbuf, &v9stat->qid);
-    v9stat->mode = stat_to_v9mode(stbuf);
-    v9stat->atime = stbuf->st_atime;
-    v9stat->mtime = stbuf->st_mtime;
-    v9stat->length = stbuf->st_size;
-
-    v9fs_string_null(&v9stat->uid);
-    v9fs_string_null(&v9stat->gid);
-    v9fs_string_null(&v9stat->muid);
-
-    v9stat->n_uid = stbuf->st_uid;
-    v9stat->n_gid = stbuf->st_gid;
-    v9stat->n_muid = 0;
-
-    v9fs_string_null(&v9stat->extension);
-
-    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_do_readlink(s, name, &v9stat->extension);
-        if (err == -1) {
-            err = -errno;
-            return err;
-        }
-        v9stat->extension.data[err] = 0;
-        v9stat->extension.size = err;
-    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
-        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
-                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
-                major(stbuf->st_rdev), minor(stbuf->st_rdev));
-    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
-        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
-                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
-    }
-
-    str = strrchr(name->data, '/');
-    if (str) {
-        str += 1;
-    } else {
-        str = name->data;
-    }
-
-    v9fs_string_sprintf(&v9stat->name, "%s", str);
-
-    v9stat->size = 61 +
-        v9fs_string_size(&v9stat->name) +
-        v9fs_string_size(&v9stat->uid) +
-        v9fs_string_size(&v9stat->gid) +
-        v9fs_string_size(&v9stat->muid) +
-        v9fs_string_size(&v9stat->extension);
-    return 0;
-}
-
-#define P9_STATS_MODE          0x00000001ULL
-#define P9_STATS_NLINK         0x00000002ULL
-#define P9_STATS_UID           0x00000004ULL
-#define P9_STATS_GID           0x00000008ULL
-#define P9_STATS_RDEV          0x00000010ULL
-#define P9_STATS_ATIME         0x00000020ULL
-#define P9_STATS_MTIME         0x00000040ULL
-#define P9_STATS_CTIME         0x00000080ULL
-#define P9_STATS_INO           0x00000100ULL
-#define P9_STATS_SIZE          0x00000200ULL
-#define P9_STATS_BLOCKS        0x00000400ULL
-
-#define P9_STATS_BTIME         0x00000800ULL
-#define P9_STATS_GEN           0x00001000ULL
-#define P9_STATS_DATA_VERSION  0x00002000ULL
-
-#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
-#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
-
-
-static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
-                            V9fsStatDotl *v9lstat)
-{
-    memset(v9lstat, 0, sizeof(*v9lstat));
-
-    v9lstat->st_mode = stbuf->st_mode;
-    v9lstat->st_nlink = stbuf->st_nlink;
-    v9lstat->st_uid = stbuf->st_uid;
-    v9lstat->st_gid = stbuf->st_gid;
-    v9lstat->st_rdev = stbuf->st_rdev;
-    v9lstat->st_size = stbuf->st_size;
-    v9lstat->st_blksize = stbuf->st_blksize;
-    v9lstat->st_blocks = stbuf->st_blocks;
-    v9lstat->st_atime_sec = stbuf->st_atime;
-    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
-    v9lstat->st_mtime_sec = stbuf->st_mtime;
-    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
-    v9lstat->st_ctime_sec = stbuf->st_ctime;
-    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
-    /* Currently we only support BASIC fields in stat */
-    v9lstat->st_result_mask = P9_STATS_BASIC;
-
-    stat_to_qid(stbuf, &v9lstat->qid);
-}
-
-static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
-{
-    while (len && *iovcnt) {
-        if (len < sg->iov_len) {
-            sg->iov_len -= len;
-            sg->iov_base += len;
-            len = 0;
-        } else {
-            len -= sg->iov_len;
-            sg++;
-            *iovcnt -= 1;
-        }
-    }
-
-    return sg;
-}
-
-static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
-{
-    int i;
-    int total = 0;
-
-    for (i = 0; i < *cnt; i++) {
-        if ((total + sg[i].iov_len) > cap) {
-            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
-            i++;
-            break;
-        }
-        total += sg[i].iov_len;
-    }
-
-    *cnt = i;
-
-    return sg;
-}
-
-static void print_sg(struct iovec *sg, int cnt)
-{
-    int i;
-
-    printf("sg[%d]: {", cnt);
-    for (i = 0; i < cnt; i++) {
-        if (i) {
-            printf(", ");
-        }
-        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
-    }
-    printf("}\n");
-}
-
-static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
-{
-    V9fsString str;
-    v9fs_string_init(&str);
-    v9fs_string_copy(&str, dst);
-    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
-    v9fs_string_free(&str);
-}
-
-static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
-{
-    V9fsString version;
-    size_t offset = 7;
-
-    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
-
-    if (!strcmp(version.data, "9P2000.u")) {
-        s->proto_version = V9FS_PROTO_2000U;
-    } else if (!strcmp(version.data, "9P2000.L")) {
-        s->proto_version = V9FS_PROTO_2000L;
-    } else {
-        v9fs_string_sprintf(&version, "unknown");
-    }
-
-    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
-    complete_pdu(s, pdu, offset);
-
-    v9fs_string_free(&version);
-}
-
-static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid, afid, n_uname;
-    V9fsString uname, aname;
-    V9fsFidState *fidp;
-    V9fsQID qid;
-    size_t offset = 7;
-    ssize_t err;
-
-    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
-
-    fidp = alloc_fid(s, fid);
-    if (fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    fidp->uid = n_uname;
-
-    v9fs_string_sprintf(&fidp->path, "%s", "/");
-    err = fid_to_qid(s, fidp, &qid);
-    if (err) {
-        err = -EINVAL;
-        free_fid(s, fid);
-        goto out;
-    }
-
-    offset += pdu_marshal(pdu, offset, "Q", &qid);
-
-    err = offset;
-out:
-    complete_pdu(s, pdu, err);
-    v9fs_string_free(&uname);
-    v9fs_string_free(&aname);
-}
-
-static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
-    if (err) {
-        goto out;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
-    err = vs->offset;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_stat_free(&vs->v9stat);
-    qemu_free(vs);
-}
-
-static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsStatState *vs;
-    ssize_t err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
-
-    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-    v9fs_stat_post_lstat(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_stat_free(&vs->v9stat);
-    qemu_free(vs);
-}
-
-static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
-                                                                int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
-    err = vs->offset;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsStatStateDotl *vs;
-    ssize_t err = 0;
-    V9fsFidState *fidp;
-    uint64_t request_mask;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
-
-    fidp = lookup_fid(s, fid);
-    if (fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    /* Currently we only support BASIC fields in stat, so there is no
-     * need to look at request_mask.
-     */
-    err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
-    v9fs_getattr_post_lstat(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-/* From Linux kernel code */
-#define ATTR_MODE    (1 << 0)
-#define ATTR_UID     (1 << 1)
-#define ATTR_GID     (1 << 2)
-#define ATTR_SIZE    (1 << 3)
-#define ATTR_ATIME   (1 << 4)
-#define ATTR_MTIME   (1 << 5)
-#define ATTR_CTIME   (1 << 6)
-#define ATTR_MASK    127
-#define ATTR_ATIME_SET  (1 << 7)
-#define ATTR_MTIME_SET  (1 << 8)
-
-static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
-                                                                  int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-    err = vs->offset;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    if (vs->v9iattr.valid & (ATTR_SIZE)) {
-        err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
-    }
-    v9fs_setattr_post_truncate(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
-                                                                   int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    /* If the only valid entry in iattr is ctime we can call
-     * chown(-1,-1) to update the ctime of the file
-     */
-    if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
-            ((vs->v9iattr.valid & ATTR_CTIME)
-            && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
-        if (!(vs->v9iattr.valid & ATTR_UID)) {
-            vs->v9iattr.uid = -1;
-        }
-        if (!(vs->v9iattr.valid & ATTR_GID)) {
-            vs->v9iattr.gid = -1;
-        }
-        err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
-                                                vs->v9iattr.gid);
-    }
-    v9fs_setattr_post_chown(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
-        struct timespec times[2];
-        if (vs->v9iattr.valid & ATTR_ATIME) {
-            if (vs->v9iattr.valid & ATTR_ATIME_SET) {
-                times[0].tv_sec = vs->v9iattr.atime_sec;
-                times[0].tv_nsec = vs->v9iattr.atime_nsec;
-            } else {
-                times[0].tv_nsec = UTIME_NOW;
-            }
-        } else {
-            times[0].tv_nsec = UTIME_OMIT;
-        }
-
-        if (vs->v9iattr.valid & ATTR_MTIME) {
-            if (vs->v9iattr.valid & ATTR_MTIME_SET) {
-                times[1].tv_sec = vs->v9iattr.mtime_sec;
-                times[1].tv_nsec = vs->v9iattr.mtime_nsec;
-            } else {
-                times[1].tv_nsec = UTIME_NOW;
-            }
-        } else {
-            times[1].tv_nsec = UTIME_OMIT;
-        }
-        err = v9fs_do_utimensat(s, &vs->fidp->path, times);
-    }
-    v9fs_setattr_post_utimensat(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsSetattrState *vs;
-    int err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    if (vs->v9iattr.valid & ATTR_MODE) {
-        err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
-    }
-
-    v9fs_setattr_post_chmod(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
-{
-    complete_pdu(s, vs->pdu, err);
-
-    if (vs->nwnames) {
-        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
-            v9fs_string_free(&vs->wnames[vs->name_idx]);
-        }
-
-        qemu_free(vs->wnames);
-        qemu_free(vs->qids);
-    }
-}
-
-static void v9fs_walk_marshal(V9fsWalkState *vs)
-{
-    int i;
-    vs->offset = 7;
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
-
-    for (i = 0; i < vs->nwnames; i++) {
-        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
-    }
-}
-
-static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
-                                                                int err)
-{
-    if (err == -1) {
-        free_fid(s, vs->newfidp->fid);
-        v9fs_string_free(&vs->path);
-        err = -ENOENT;
-        goto out;
-    }
-
-    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
-
-    vs->name_idx++;
-    if (vs->name_idx < vs->nwnames) {
-        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
-                                            vs->wnames[vs->name_idx].data);
-        v9fs_string_copy(&vs->newfidp->path, &vs->path);
-
-        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
-        v9fs_walk_post_newfid_lstat(s, vs, err);
-        return;
-    }
-
-    v9fs_string_free(&vs->path);
-    v9fs_walk_marshal(vs);
-    err = vs->offset;
-out:
-    v9fs_walk_complete(s, vs, err);
-}
-
-static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
-        int err)
-{
-    if (err == -1) {
-        v9fs_string_free(&vs->path);
-        err = -ENOENT;
-        goto out;
-    }
-
-    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
-    vs->name_idx++;
-    if (vs->name_idx < vs->nwnames) {
-
-        v9fs_string_sprintf(&vs->path, "%s/%s",
-                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
-        v9fs_string_copy(&vs->fidp->path, &vs->path);
-
-        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-        v9fs_walk_post_oldfid_lstat(s, vs, err);
-        return;
-    }
-
-    v9fs_string_free(&vs->path);
-    v9fs_walk_marshal(vs);
-    err = vs->offset;
-out:
-    v9fs_walk_complete(s, vs, err);
-}
-
-static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid, newfid;
-    V9fsWalkState *vs;
-    int err = 0;
-    int i;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->wnames = NULL;
-    vs->qids = NULL;
-    vs->offset = 7;
-
-    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
-                                            &newfid, &vs->nwnames);
-
-    if (vs->nwnames) {
-        vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
-
-        vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
-
-        for (i = 0; i < vs->nwnames; i++) {
-            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
-                                            &vs->wnames[i]);
-        }
-    }
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    /* FIXME: is this really valid? */
-    if (fid == newfid) {
-
-        BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
-        v9fs_string_init(&vs->path);
-        vs->name_idx = 0;
-
-        if (vs->name_idx < vs->nwnames) {
-            v9fs_string_sprintf(&vs->path, "%s/%s",
-                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
-            v9fs_string_copy(&vs->fidp->path, &vs->path);
-
-            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-            v9fs_walk_post_oldfid_lstat(s, vs, err);
-            return;
-        }
-    } else {
-        vs->newfidp = alloc_fid(s, newfid);
-        if (vs->newfidp == NULL) {
-            err = -EINVAL;
-            goto out;
-        }
-
-        vs->newfidp->uid = vs->fidp->uid;
-        v9fs_string_init(&vs->path);
-        vs->name_idx = 0;
-        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
-
-        if (vs->name_idx < vs->nwnames) {
-            v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
-                                vs->wnames[vs->name_idx].data);
-            v9fs_string_copy(&vs->newfidp->path, &vs->path);
-
-            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
-            v9fs_walk_post_newfid_lstat(s, vs, err);
-            return;
-        }
-    }
-
-    v9fs_walk_marshal(vs);
-    err = vs->offset;
-out:
-    v9fs_walk_complete(s, vs, err);
-}
-
-static int32_t get_iounit(V9fsState *s, V9fsString *name)
-{
-    struct statfs stbuf;
-    int32_t iounit = 0;
-
-    /*
-     * iounit should be multiples of f_bsize (host filesystem block size
-     * and as well as less than (client msize - P9_IOHDRSZ))
-     */
-    if (!v9fs_do_statfs(s, name, &stbuf)) {
-        iounit = stbuf.f_bsize;
-        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
-    }
-
-    if (!iounit) {
-        iounit = s->msize - P9_IOHDRSZ;
-    }
-    return iounit;
-}
-
-static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
-{
-    if (vs->fidp->fs.dir == NULL) {
-        err = -errno;
-        goto out;
-    }
-    vs->fidp->fid_type = P9_FID_DIR;
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-
-}
-
-static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
-{
-    int err;
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
-    err = vs->offset;
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
-{
-    if (vs->fidp->fs.fd == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->fidp->fid_type = P9_FID_FILE;
-    vs->iounit = get_iounit(s, &vs->fidp->path);
-    v9fs_open_post_getiounit(s, vs);
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
-{
-    int flags;
-
-    if (err) {
-        err = -errno;
-        goto out;
-    }
-
-    stat_to_qid(&vs->stbuf, &vs->qid);
-
-    if (S_ISDIR(vs->stbuf.st_mode)) {
-        vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
-        v9fs_open_post_opendir(s, vs, err);
-    } else {
-        if (s->proto_version == V9FS_PROTO_2000L) {
-            flags = vs->mode;
-            flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
-            /* Ignore direct disk access hint until the server supports it. */
-            flags &= ~O_DIRECT;
-        } else {
-            flags = omode_to_uflags(vs->mode);
-        }
-        vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
-        v9fs_open_post_open(s, vs, err);
-    }
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsOpenState *vs;
-    ssize_t err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-    vs->mode = 0;
-
-    if (s->proto_version == V9FS_PROTO_2000L) {
-        pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
-    } else {
-        pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
-    }
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
-
-    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-
-    v9fs_open_post_lstat(s, vs, err);
-    return;
-out:
-    complete_pdu(s, pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
-{
-    if (err == 0) {
-        v9fs_string_copy(&vs->fidp->path, &vs->fullname);
-        stat_to_qid(&vs->stbuf, &vs->qid);
-        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
-                &vs->iounit);
-        err = vs->offset;
-    } else {
-        vs->fidp->fid_type = P9_FID_NONE;
-        err = -errno;
-        if (vs->fidp->fs.fd > 0) {
-            close(vs->fidp->fs.fd);
-        }
-    }
-
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->fullname);
-    qemu_free(vs);
-}
-
-static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
-        int err)
-{
-    if (err) {
-        err = -errno;
-        goto out;
-    }
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-
-out:
-    v9fs_post_lcreate(s, vs, err);
-}
-
-static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
-        int err)
-{
-    if (vs->fidp->fs.fd == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->fidp->fid_type = P9_FID_FILE;
-    vs->iounit =  get_iounit(s, &vs->fullname);
-    v9fs_lcreate_post_get_iounit(s, vs, err);
-    return;
-
-out:
-    v9fs_post_lcreate(s, vs, err);
-}
-
-static void v9fs_lcreate(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t dfid, flags, mode;
-    gid_t gid;
-    V9fsLcreateState *vs;
-    ssize_t err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    v9fs_string_init(&vs->fullname);
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
-            &mode, &gid);
-
-    vs->fidp = lookup_fid(s, dfid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
-             vs->name.data);
-
-    /* Ignore direct disk access hint until the server supports it. */
-    flags &= ~O_DIRECT;
-
-    vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
-            gid, flags, mode);
-    v9fs_lcreate_post_do_open2(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
-{
-    if (err == -1) {
-        err = -errno;
-    }
-    complete_pdu(s, pdu, err);
-}
-
-static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    size_t offset = 7;
-    V9fsFidState *fidp;
-    int datasync;
-    int err;
-
-    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
-    fidp = lookup_fid(s, fid);
-    if (fidp == NULL) {
-        err = -ENOENT;
-        v9fs_post_do_fsync(s, pdu, err);
-        return;
-    }
-    err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
-    v9fs_post_do_fsync(s, pdu, err);
-}
-
-static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    size_t offset = 7;
-    int err;
-
-    pdu_unmarshal(pdu, offset, "d", &fid);
-
-    err = free_fid(s, fid);
-    if (err < 0) {
-        goto out;
-    }
-
-    offset = 7;
-    err = offset;
-out:
-    complete_pdu(s, pdu, err);
-}
-
-static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
-
-static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
-{
-    if (err) {
-        goto out;
-    }
-    v9fs_stat_free(&vs->v9stat);
-    v9fs_string_free(&vs->name);
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
-    vs->offset += vs->count;
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-    return;
-}
-
-static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
-                                    ssize_t err)
-{
-    if (err) {
-        err = -errno;
-        goto out;
-    }
-    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
-    if (err) {
-        goto out;
-    }
-
-    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
-                            &vs->v9stat);
-    if ((vs->len != (vs->v9stat.size + 2)) ||
-            ((vs->count + vs->len) > vs->max_count)) {
-        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
-        v9fs_read_post_seekdir(s, vs, err);
-        return;
-    }
-    vs->count += vs->len;
-    v9fs_stat_free(&vs->v9stat);
-    v9fs_string_free(&vs->name);
-    vs->dir_pos = vs->dent->d_off;
-    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
-    v9fs_read_post_readdir(s, vs, err);
-    return;
-out:
-    v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
-    v9fs_read_post_seekdir(s, vs, err);
-    return;
-
-}
-
-static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
-{
-    if (vs->dent) {
-        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
-        v9fs_string_init(&vs->name);
-        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
-                            vs->dent->d_name);
-        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
-        v9fs_read_post_dir_lstat(s, vs, err);
-        return;
-    }
-
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
-    vs->offset += vs->count;
-    err = vs->offset;
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-    return;
-}
-
-static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
-{
-    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
-    v9fs_read_post_readdir(s, vs, err);
-    return;
-}
-
-static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
-                                       ssize_t err)
-{
-    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
-    v9fs_read_post_telldir(s, vs, err);
-    return;
-}
-
-static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
-{
-    if (err  < 0) {
-        /* IO error return the error */
-        err = -errno;
-        goto out;
-    }
-    vs->total += vs->len;
-    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
-    if (vs->total < vs->count && vs->len > 0) {
-        do {
-            if (0) {
-                print_sg(vs->sg, vs->cnt);
-            }
-            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
-                      vs->off);
-            if (vs->len > 0) {
-                vs->off += vs->len;
-            }
-        } while (vs->len == -1 && errno == EINTR);
-        if (vs->len == -1) {
-            err  = -errno;
-        }
-        v9fs_read_post_preadv(s, vs, err);
-        return;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
-    vs->offset += vs->count;
-    err = vs->offset;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
-{
-    ssize_t err = 0;
-    int read_count;
-    int64_t xattr_len;
-
-    xattr_len = vs->fidp->fs.xattr.len;
-    read_count = xattr_len - vs->off;
-    if (read_count > vs->count) {
-        read_count = vs->count;
-    } else if (read_count < 0) {
-        /*
-         * read beyond XATTR value
-         */
-        read_count = 0;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
-    vs->offset += pdu_pack(vs->pdu, vs->offset,
-                           ((char *)vs->fidp->fs.xattr.value) + vs->off,
-                           read_count);
-    err = vs->offset;
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsReadState *vs;
-    ssize_t err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-    vs->total = 0;
-    vs->len = 0;
-    vs->count = 0;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    if (vs->fidp->fid_type == P9_FID_DIR) {
-        vs->max_count = vs->count;
-        vs->count = 0;
-        if (vs->off == 0) {
-            v9fs_do_rewinddir(s, vs->fidp->fs.dir);
-        }
-        v9fs_read_post_rewinddir(s, vs, err);
-        return;
-    } else if (vs->fidp->fid_type == P9_FID_FILE) {
-        vs->sg = vs->iov;
-        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
-        vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-        if (vs->total <= vs->count) {
-            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
-                                    vs->off);
-            if (vs->len > 0) {
-                vs->off += vs->len;
-            }
-            err = vs->len;
-            v9fs_read_post_preadv(s, vs, err);
-        }
-        return;
-    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
-        v9fs_xattr_read(s, vs);
-        return;
-    } else {
-        err = -EINVAL;
-    }
-out:
-    complete_pdu(s, pdu, err);
-    qemu_free(vs);
-}
-
-typedef struct V9fsReadDirState {
-    V9fsPDU *pdu;
-    V9fsFidState *fidp;
-    V9fsQID qid;
-    off_t saved_dir_pos;
-    struct dirent *dent;
-    int32_t count;
-    int32_t max_count;
-    size_t offset;
-    int64_t initial_offset;
-    V9fsString name;
-} V9fsReadDirState;
-
-static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
-{
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
-    vs->offset += vs->count;
-    complete_pdu(s, vs->pdu, vs->offset);
-    qemu_free(vs);
-    return;
-}
-
-/* Size of each dirent on the wire: size of qid (13) + size of offset (8)
- * size of type (1) + size of name.size (2) + strlen(name.data)
- */
-#define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
-
-static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
-{
-    int len;
-    size_t size;
-
-    if (vs->dent) {
-        v9fs_string_init(&vs->name);
-        v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
-
-        if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
-            /* Ran out of buffer. Set dir back to old position and return */
-            v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->saved_dir_pos);
-            v9fs_readdir_post_seekdir(s, vs);
-            return;
-        }
-
-        /* Fill up just the path field of qid because the client uses
-         * only that. To fill the entire qid structure we will have
-         * to stat each dirent found, which is expensive
-         */
-        size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
-        memcpy(&vs->qid.path, &vs->dent->d_ino, size);
-        /* Fill the other fields with dummy values */
-        vs->qid.type = 0;
-        vs->qid.version = 0;
-
-        len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
-                              &vs->qid, vs->dent->d_off,
-                              vs->dent->d_type, &vs->name);
-        vs->count += len;
-        v9fs_string_free(&vs->name);
-        vs->saved_dir_pos = vs->dent->d_off;
-        vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
-        v9fs_readdir_post_readdir(s, vs);
-        return;
-    }
-
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
-    vs->offset += vs->count;
-    complete_pdu(s, vs->pdu, vs->offset);
-    qemu_free(vs);
-    return;
-}
-
-static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
-{
-    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
-    v9fs_readdir_post_readdir(s, vs);
-    return;
-}
-
-static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
-{
-    vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
-    v9fs_readdir_post_telldir(s, vs);
-    return;
-}
-
-static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsReadDirState *vs;
-    ssize_t err = 0;
-    size_t offset = 7;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-    vs->count = 0;
-
-    pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
-                                                        &vs->max_count);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL || !(vs->fidp->fs.dir)) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    if (vs->initial_offset == 0) {
-        v9fs_do_rewinddir(s, vs->fidp->fs.dir);
-    } else {
-        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->initial_offset);
-    }
-
-    v9fs_readdir_post_setdir(s, vs);
-    return;
-
-out:
-    complete_pdu(s, pdu, err);
-    qemu_free(vs);
-    return;
-}
-
-static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
-                                   ssize_t err)
-{
-    if (err  < 0) {
-        /* IO error return the error */
-        err = -errno;
-        goto out;
-    }
-    vs->total += vs->len;
-    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
-    if (vs->total < vs->count && vs->len > 0) {
-        do {
-            if (0) {
-                print_sg(vs->sg, vs->cnt);
-            }
-            vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
-                      vs->off);
-            if (vs->len > 0) {
-                vs->off += vs->len;
-            }
-        } while (vs->len == -1 && errno == EINTR);
-        if (vs->len == -1) {
-            err  = -errno;
-        }
-        v9fs_write_post_pwritev(s, vs, err);
-        return;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
-{
-    int i, to_copy;
-    ssize_t err = 0;
-    int write_count;
-    int64_t xattr_len;
-
-    xattr_len = vs->fidp->fs.xattr.len;
-    write_count = xattr_len - vs->off;
-    if (write_count > vs->count) {
-        write_count = vs->count;
-    } else if (write_count < 0) {
-        /*
-         * write beyond XATTR value len specified in
-         * xattrcreate
-         */
-        err = -ENOSPC;
-        goto out;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
-    err = vs->offset;
-    vs->fidp->fs.xattr.copied_len += write_count;
-    /*
-     * Now copy the content from sg list
-     */
-    for (i = 0; i < vs->cnt; i++) {
-        if (write_count > vs->sg[i].iov_len) {
-            to_copy = vs->sg[i].iov_len;
-        } else {
-            to_copy = write_count;
-        }
-        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
-               vs->sg[i].iov_base, to_copy);
-        /* updating vs->off since we are not using below */
-        vs->off += to_copy;
-        write_count -= to_copy;
-    }
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsWriteState *vs;
-    ssize_t err;
-
-    vs = qemu_malloc(sizeof(*vs));
-
-    vs->pdu = pdu;
-    vs->offset = 7;
-    vs->sg = vs->iov;
-    vs->total = 0;
-    vs->len = 0;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
-                  vs->sg, &vs->cnt);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    if (vs->fidp->fid_type == P9_FID_FILE) {
-        if (vs->fidp->fs.fd == -1) {
-            err = -EINVAL;
-            goto out;
-        }
-    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
-        /*
-         * setxattr operation
-         */
-        v9fs_xattr_write(s, vs);
-        return;
-    } else {
-        err = -EINVAL;
-        goto out;
-    }
-    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-    if (vs->total <= vs->count) {
-        vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
-        if (vs->len > 0) {
-            vs->off += vs->len;
-        }
-        err = vs->len;
-        v9fs_write_post_pwritev(s, vs, err);
-    }
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
-{
-    int err;
-    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
-    stat_to_qid(&vs->stbuf, &vs->qid);
-
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
-    err = vs->offset;
-
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->extension);
-    v9fs_string_free(&vs->fullname);
-    qemu_free(vs);
-}
-
-static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (err == 0) {
-        vs->iounit = get_iounit(s, &vs->fidp->path);
-        v9fs_create_post_getiounit(s, vs);
-        return;
-    }
-
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->extension);
-    v9fs_string_free(&vs->fullname);
-    qemu_free(vs);
-}
-
-static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (err) {
-        err = -errno;
-    }
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
-                                                                    int err)
-{
-    if (!vs->fidp->fs.dir) {
-        err = -errno;
-    }
-    vs->fidp->fid_type = P9_FID_DIR;
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
-                                                                    int err)
-{
-    if (err) {
-        err = -errno;
-        goto out;
-    }
-
-    vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
-    v9fs_create_post_opendir(s, vs, err);
-    return;
-
-out:
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (err) {
-        err = -errno;
-        goto out;
-    }
-
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-    v9fs_create_post_dir_lstat(s, vs, err);
-    return;
-
-out:
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (err) {
-        vs->fidp->fid_type = P9_FID_NONE;
-        close(vs->fidp->fs.fd);
-        err = -errno;
-    }
-    v9fs_post_create(s, vs, err);
-    return;
-}
-
-static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (vs->fidp->fs.fd == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->fidp->fid_type = P9_FID_FILE;
-    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
-    v9fs_create_post_fstat(s, vs, err);
-
-    return;
-
-out:
-    v9fs_post_create(s, vs, err);
-
-}
-
-static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
-{
-
-    if (err == 0 || errno != ENOENT) {
-        err = -errno;
-        goto out;
-    }
-
-    if (vs->perm & P9_STAT_MODE_DIR) {
-        err = v9fs_do_mkdir(s, vs->fullname.data, vs->perm & 0777,
-                vs->fidp->uid, -1);
-        v9fs_create_post_mkdir(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
-                vs->fullname.data, -1);
-        v9fs_create_post_perms(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_LINK) {
-        int32_t nfid = atoi(vs->extension.data);
-        V9fsFidState *nfidp = lookup_fid(s, nfid);
-        if (nfidp == NULL) {
-            err = -errno;
-            v9fs_post_create(s, vs, err);
-        }
-        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
-        v9fs_create_post_perms(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
-        char ctype;
-        uint32_t major, minor;
-        mode_t nmode = 0;
-
-        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
-                                        &minor) != 3) {
-            err = -errno;
-            v9fs_post_create(s, vs, err);
-        }
-
-        switch (ctype) {
-        case 'c':
-            nmode = S_IFCHR;
-            break;
-        case 'b':
-            nmode = S_IFBLK;
-            break;
-        default:
-            err = -EIO;
-            v9fs_post_create(s, vs, err);
-        }
-
-        nmode |= vs->perm & 0777;
-        err = v9fs_do_mknod(s, vs->fullname.data, nmode,
-                makedev(major, minor), vs->fidp->uid, -1);
-        v9fs_create_post_perms(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
-        err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
-                0, vs->fidp->uid, -1);
-        v9fs_post_create(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
-        err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
-                0, vs->fidp->uid, -1);
-        v9fs_post_create(s, vs, err);
-    } else {
-        vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
-                -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
-
-        v9fs_create_post_open2(s, vs, err);
-    }
-
-    return;
-
-out:
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsCreateState *vs;
-    int err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    v9fs_string_init(&vs->fullname);
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
-                                &vs->perm, &vs->mode, &vs->extension);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
-                                                        vs->name.data);
-
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-    v9fs_create_post_lstat(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->extension);
-    qemu_free(vs);
-}
-
-static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
-{
-    if (err == 0) {
-        stat_to_qid(&vs->stbuf, &vs->qid);
-        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
-        err = vs->offset;
-    } else {
-        err = -errno;
-    }
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->symname);
-    v9fs_string_free(&vs->fullname);
-    qemu_free(vs);
-}
-
-static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
-        int err)
-{
-    if (err) {
-        goto out;
-    }
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-out:
-    v9fs_post_symlink(s, vs, err);
-}
-
-static void v9fs_symlink(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t dfid;
-    V9fsSymlinkState *vs;
-    int err = 0;
-    gid_t gid;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    v9fs_string_init(&vs->fullname);
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
-            &vs->symname, &gid);
-
-    vs->dfidp = lookup_fid(s, dfid);
-    if (vs->dfidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
-            vs->name.data);
-    err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
-            vs->fullname.data, gid);
-    v9fs_symlink_post_do_symlink(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->symname);
-    qemu_free(vs);
-}
-
-static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
-{
-    /* A nop call with no return */
-    complete_pdu(s, pdu, 7);
-}
-
-static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t dfid, oldfid;
-    V9fsFidState *dfidp, *oldfidp;
-    V9fsString name, fullname;
-    size_t offset = 7;
-    int err = 0;
-
-    v9fs_string_init(&fullname);
-
-    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
-
-    dfidp = lookup_fid(s, dfid);
-    if (dfidp == NULL) {
-        err = -errno;
-        goto out;
-    }
-
-    oldfidp = lookup_fid(s, oldfid);
-    if (oldfidp == NULL) {
-        err = -errno;
-        goto out;
-    }
-
-    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
-    err = offset;
-    err = v9fs_do_link(s, &oldfidp->path, &fullname);
-    if (err) {
-        err = -errno;
-    }
-    v9fs_string_free(&fullname);
-
-out:
-    v9fs_string_free(&name);
-    complete_pdu(s, pdu, err);
-}
-
-static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
-                                                                int err)
-{
-    if (err < 0) {
-        err = -errno;
-    } else {
-        err = vs->offset;
-    }
-
-    /* For TREMOVE we need to clunk the fid even on failed remove */
-    free_fid(s, vs->fidp->fid);
-
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsRemoveState *vs;
-    int err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    err = v9fs_do_remove(s, &vs->fidp->path);
-    v9fs_remove_post_remove(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-
-    err = vs->offset;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-    if (vs->v9stat.length != -1) {
-        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
-            err = -errno;
-        }
-    }
-    v9fs_wstat_post_truncate(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
-{
-    int err = 0;
-    char *old_name, *new_name;
-    char *end;
-
-    if (vs->newdirfid != -1) {
-        V9fsFidState *dirfidp;
-        dirfidp = lookup_fid(s, vs->newdirfid);
-
-        if (dirfidp == NULL) {
-            err = -ENOENT;
-            goto out;
-        }
-
-        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
-
-        new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
-
-        strcpy(new_name, dirfidp->path.data);
-        strcat(new_name, "/");
-        strcat(new_name + dirfidp->path.size, vs->name.data);
-    } else {
-        old_name = vs->fidp->path.data;
-        end = strrchr(old_name, '/');
-        if (end) {
-            end++;
-        } else {
-            end = old_name;
-        }
-        new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
-
-        strncat(new_name, old_name, end - old_name);
-        strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
-    }
-
-    v9fs_string_free(&vs->name);
-    vs->name.data = qemu_strdup(new_name);
-    vs->name.size = strlen(new_name);
-
-    if (strcmp(new_name, vs->fidp->path.data) != 0) {
-        if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
-            err = -errno;
-        } else {
-            V9fsFidState *fidp;
-            /*
-            * Fixup fid's pointing to the old name to
-            * start pointing to the new name
-            */
-            for (fidp = s->fid_list; fidp; fidp = fidp->next) {
-                if (vs->fidp == fidp) {
-                    /*
-                    * we replace name of this fid towards the end
-                    * so that our below strcmp will work
-                    */
-                    continue;
-                }
-                if (!strncmp(vs->fidp->path.data, fidp->path.data,
-                    strlen(vs->fidp->path.data))) {
-                    /* replace the name */
-                    v9fs_fix_path(&fidp->path, &vs->name,
-                                  strlen(vs->fidp->path.data));
-                }
-            }
-            v9fs_string_copy(&vs->fidp->path, &vs->name);
-        }
-    }
-out:
-    v9fs_string_free(&vs->name);
-    return err;
-}
-
-static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
-{
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-
-    if (vs->v9stat.name.size != 0) {
-        V9fsRenameState *vr;
-
-        vr = qemu_mallocz(sizeof(V9fsRenameState));
-        vr->newdirfid = -1;
-        vr->pdu = vs->pdu;
-        vr->fidp = vs->fidp;
-        vr->offset = vs->offset;
-        vr->name.size = vs->v9stat.name.size;
-        vr->name.data = qemu_strdup(vs->v9stat.name.data);
-
-        err = v9fs_complete_rename(s, vr);
-        qemu_free(vr);
-    }
-    v9fs_wstat_post_rename(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_rename(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsRenameState *vs;
-    ssize_t err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
-
-    err = v9fs_complete_rename(s, vs);
-    v9fs_rename_post_rename(s, vs, err);
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-
-    if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
-        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
-                    vs->v9stat.n_gid)) {
-            err = -errno;
-        }
-    }
-    v9fs_wstat_post_chown(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-
-    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
-        struct timespec times[2];
-        if (vs->v9stat.atime != -1) {
-            times[0].tv_sec = vs->v9stat.atime;
-            times[0].tv_nsec = 0;
-        } else {
-            times[0].tv_nsec = UTIME_OMIT;
-        }
-        if (vs->v9stat.mtime != -1) {
-            times[1].tv_sec = vs->v9stat.mtime;
-            times[1].tv_nsec = 0;
-        } else {
-            times[1].tv_nsec = UTIME_OMIT;
-        }
-
-        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
-            err = -errno;
-        }
-    }
-
-    v9fs_wstat_post_utime(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-    }
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    uint32_t v9_mode;
-
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    v9_mode = stat_to_v9mode(&vs->stbuf);
-
-    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
-        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
-            /* Attempting to change the type */
-            err = -EIO;
-            goto out;
-    }
-
-    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
-                    &vs->v9stat.extension))) {
-            err = -errno;
-     }
-    v9fs_wstat_post_chmod(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsWstatState *vs;
-    int err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    /* do we need to sync the file? */
-    if (donttouch_stat(&vs->v9stat)) {
-        err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
-        v9fs_wstat_post_fsync(s, vs, err);
-        return;
-    }
-
-    if (vs->v9stat.mode != -1) {
-        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-        v9fs_wstat_post_lstat(s, vs, err);
-        return;
-    }
-
-    v9fs_wstat_post_chmod(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
-{
-    int32_t bsize_factor;
-
-    if (err) {
-        err = -errno;
-        goto out;
-    }
-
-    /*
-     * compute bsize factor based on host file system block size
-     * and client msize
-     */
-    bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
-    if (!bsize_factor) {
-        bsize_factor = 1;
-    }
-    vs->v9statfs.f_type = vs->stbuf.f_type;
-    vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
-    vs->v9statfs.f_bsize *= bsize_factor;
-    /*
-     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
-     * adjust(divide) the number of blocks, free blocks and available
-     * blocks by bsize factor
-     */
-    vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
-    vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
-    vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
-    vs->v9statfs.f_files = vs->stbuf.f_files;
-    vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
-    vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
-                       (unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
-    vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
-
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
-         vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
-         vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
-         vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
-         vs->v9statfs.f_namelen);
-
-out:
-    complete_pdu(s, vs->pdu, vs->offset);
-    qemu_free(vs);
-}
-
-static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
-{
-    V9fsStatfsState *vs;
-    ssize_t err = 0;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
-
-    pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
-
-    vs->fidp = lookup_fid(s, vs->fid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
-    v9fs_statfs_post_statfs(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-static void v9fs_mknod_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    stat_to_qid(&vs->stbuf, &vs->qid);
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->fullname);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_mknod_post_mknod(V9fsState *s, V9fsMkState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-    v9fs_mknod_post_lstat(s, vs, err);
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->fullname);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_mknod(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsMkState *vs;
-    int err = 0;
-    V9fsFidState *fidp;
-    gid_t gid;
-    int mode;
-    int major, minor;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    v9fs_string_init(&vs->fullname);
-    pdu_unmarshal(vs->pdu, vs->offset, "dsdddd", &fid, &vs->name, &mode,
-        &major, &minor, &gid);
-
-    fidp = lookup_fid(s, fid);
-    if (fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
-    err = v9fs_do_mknod(s, vs->fullname.data, mode, makedev(major, minor),
-        fidp->uid, gid);
-    v9fs_mknod_post_mknod(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->fullname);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-/*
- * Implement posix byte range locking code
- * Server side handling of locking code is very simple, because 9p server in
- * QEMU can handle only one client. And most of the lock handling
- * (like conflict, merging) etc is done by the VFS layer itself, so no need to
- * do any thing in * qemu 9p server side lock code path.
- * So when a TLOCK request comes, always return success
- */
-
-static void v9fs_lock(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid, err = 0;
-    V9fsLockState *vs;
-
-    vs = qemu_mallocz(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    vs->flock = qemu_malloc(sizeof(*vs->flock));
-    pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
-                &vs->flock->flags, &vs->flock->start, &vs->flock->length,
-                            &vs->flock->proc_id, &vs->flock->client_id);
-
-    vs->status = P9_LOCK_ERROR;
-
-    /* We support only block flag now (that too ignored currently) */
-    if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
-        err = -EINVAL;
-        goto out;
-    }
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
-    if (err < 0) {
-        err = -errno;
-        goto out;
-    }
-    vs->status = P9_LOCK_SUCCESS;
-out:
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs->flock);
-    qemu_free(vs);
-}
-
-/*
- * When a TGETLOCK request comes, always return success because all lock
- * handling is done by client's VFS layer.
- */
-
-static void v9fs_getlock(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid, err = 0;
-    V9fsGetlockState *vs;
-
-    vs = qemu_mallocz(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    vs->glock = qemu_malloc(sizeof(*vs->glock));
-    pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
-                &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
-               &vs->glock->client_id);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
-    if (err < 0) {
-        err = -errno;
-        goto out;
-    }
-    vs->glock->type = F_UNLCK;
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
-                vs->glock->start, vs->glock->length, vs->glock->proc_id,
-               &vs->glock->client_id);
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs->glock);
-    qemu_free(vs);
-}
-
-static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    stat_to_qid(&vs->stbuf, &vs->qid);
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->fullname);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_mkdir_post_mkdir(V9fsState *s, V9fsMkState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-    v9fs_mkdir_post_lstat(s, vs, err);
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->fullname);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_mkdir(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsMkState *vs;
-    int err = 0;
-    V9fsFidState *fidp;
-    gid_t gid;
-    int mode;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    v9fs_string_init(&vs->fullname);
-    pdu_unmarshal(vs->pdu, vs->offset, "dsdd", &fid, &vs->name, &mode,
-        &gid);
-
-    fidp = lookup_fid(s, fid);
-    if (fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
-    err = v9fs_do_mkdir(s, vs->fullname.data, mode, fidp->uid, gid);
-    v9fs_mkdir_post_mkdir(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->fullname);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_post_xattr_getvalue(V9fsState *s, V9fsXattrState *vs, int err)
-{
-
-    if (err < 0) {
-        err = -errno;
-        free_fid(s, vs->xattr_fidp->fid);
-        goto out;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-    return;
-}
-
-static void v9fs_post_xattr_check(V9fsState *s, V9fsXattrState *vs, ssize_t err)
-{
-    if (err < 0) {
-        err = -errno;
-        free_fid(s, vs->xattr_fidp->fid);
-        goto out;
-    }
-    /*
-     * Read the xattr value
-     */
-    vs->xattr_fidp->fs.xattr.len = vs->size;
-    vs->xattr_fidp->fid_type = P9_FID_XATTR;
-    vs->xattr_fidp->fs.xattr.copied_len = -1;
-    if (vs->size) {
-        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
-        err = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
-                                &vs->name, vs->xattr_fidp->fs.xattr.value,
-                                vs->xattr_fidp->fs.xattr.len);
-    }
-    v9fs_post_xattr_getvalue(s, vs, err);
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_post_lxattr_getvalue(V9fsState *s,
-                                      V9fsXattrState *vs, int err)
-{
-    if (err < 0) {
-        err = -errno;
-        free_fid(s, vs->xattr_fidp->fid);
-        goto out;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-    return;
-}
-
-static void v9fs_post_lxattr_check(V9fsState *s,
-                                   V9fsXattrState *vs, ssize_t err)
-{
-    if (err < 0) {
-        err = -errno;
-        free_fid(s, vs->xattr_fidp->fid);
-        goto out;
-    }
-    /*
-     * Read the xattr value
-     */
-    vs->xattr_fidp->fs.xattr.len = vs->size;
-    vs->xattr_fidp->fid_type = P9_FID_XATTR;
-    vs->xattr_fidp->fs.xattr.copied_len = -1;
-    if (vs->size) {
-        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
-        err = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
-                                 vs->xattr_fidp->fs.xattr.value,
-                                 vs->xattr_fidp->fs.xattr.len);
-    }
-    v9fs_post_lxattr_getvalue(s, vs, err);
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_xattrwalk(V9fsState *s, V9fsPDU *pdu)
-{
-    ssize_t err = 0;
-    V9fsXattrState *vs;
-    int32_t fid, newfid;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &newfid, &vs->name);
-    vs->file_fidp = lookup_fid(s, fid);
-    if (vs->file_fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    vs->xattr_fidp = alloc_fid(s, newfid);
-    if (vs->xattr_fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    v9fs_string_copy(&vs->xattr_fidp->path, &vs->file_fidp->path);
-    if (vs->name.data[0] == 0) {
-        /*
-         * listxattr request. Get the size first
-         */
-        vs->size = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
-                                      NULL, 0);
-        if (vs->size < 0) {
-            err = vs->size;
-        }
-        v9fs_post_lxattr_check(s, vs, err);
-        return;
-    } else {
-        /*
-         * specific xattr fid. We check for xattr
-         * presence also collect the xattr size
-         */
-        vs->size = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
-                                     &vs->name, NULL, 0);
-        if (vs->size < 0) {
-            err = vs->size;
-        }
-        v9fs_post_xattr_check(s, vs, err);
-        return;
-    }
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
-{
-    int flags;
-    int32_t fid;
-    ssize_t err = 0;
-    V9fsXattrState *vs;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
-                  &fid, &vs->name, &vs->size, &flags);
-
-    vs->file_fidp = lookup_fid(s, fid);
-    if (vs->file_fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    /* Make the file fid point to xattr */
-    vs->xattr_fidp = vs->file_fidp;
-    vs->xattr_fidp->fid_type = P9_FID_XATTR;
-    vs->xattr_fidp->fs.xattr.copied_len = 0;
-    vs->xattr_fidp->fs.xattr.len = vs->size;
-    vs->xattr_fidp->fs.xattr.flags = flags;
-    v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
-    v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
-    if (vs->size)
-        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
-    else
-        vs->xattr_fidp->fs.xattr.value = NULL;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    qemu_free(vs);
-}
-
-static void v9fs_readlink_post_readlink(V9fsState *s, V9fsReadLinkState *vs,
-                                                    int err)
-{
-    if (err < 0) {
-        err = -errno;
-        goto out;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "s", &vs->target);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->target);
-    qemu_free(vs);
-}
-
-static void v9fs_readlink(V9fsState *s, V9fsPDU *pdu)
-{
-    int32_t fid;
-    V9fsReadLinkState *vs;
-    int err = 0;
-    V9fsFidState *fidp;
-
-    vs = qemu_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
-
-    fidp = lookup_fid(s, fid);
-    if (fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    v9fs_string_init(&vs->target);
-    err = v9fs_do_readlink(s, &fidp->path, &vs->target);
-    v9fs_readlink_post_readlink(s, vs, err);
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
-typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
-
-static pdu_handler_t *pdu_handlers[] = {
-    [P9_TREADDIR] = v9fs_readdir,
-    [P9_TSTATFS] = v9fs_statfs,
-    [P9_TGETATTR] = v9fs_getattr,
-    [P9_TSETATTR] = v9fs_setattr,
-    [P9_TXATTRWALK] = v9fs_xattrwalk,
-    [P9_TXATTRCREATE] = v9fs_xattrcreate,
-    [P9_TMKNOD] = v9fs_mknod,
-    [P9_TRENAME] = v9fs_rename,
-    [P9_TLOCK] = v9fs_lock,
-    [P9_TGETLOCK] = v9fs_getlock,
-    [P9_TREADLINK] = v9fs_readlink,
-    [P9_TMKDIR] = v9fs_mkdir,
-    [P9_TVERSION] = v9fs_version,
-    [P9_TLOPEN] = v9fs_open,
-    [P9_TATTACH] = v9fs_attach,
-    [P9_TSTAT] = v9fs_stat,
-    [P9_TWALK] = v9fs_walk,
-    [P9_TCLUNK] = v9fs_clunk,
-    [P9_TFSYNC] = v9fs_fsync,
-    [P9_TOPEN] = v9fs_open,
-    [P9_TREAD] = v9fs_read,
-#if 0
-    [P9_TAUTH] = v9fs_auth,
-#endif
-    [P9_TFLUSH] = v9fs_flush,
-    [P9_TLINK] = v9fs_link,
-    [P9_TSYMLINK] = v9fs_symlink,
-    [P9_TCREATE] = v9fs_create,
-    [P9_TLCREATE] = v9fs_lcreate,
-    [P9_TWRITE] = v9fs_write,
-    [P9_TWSTAT] = v9fs_wstat,
-    [P9_TREMOVE] = v9fs_remove,
-};
-
-static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
-{
-    pdu_handler_t *handler;
-
-    if (debug_9p_pdu) {
-        pprint_pdu(pdu);
-    }
-
-    BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
-
-    handler = pdu_handlers[pdu->id];
-    BUG_ON(handler == NULL);
-
-    handler(s, pdu);
-}
-
-static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
-{
-    V9fsState *s = (V9fsState *)vdev;
-    V9fsPDU *pdu;
-    ssize_t len;
-
-    while ((pdu = alloc_pdu(s)) &&
-            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
-        uint8_t *ptr;
-
-        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
-        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
-
-        ptr = pdu->elem.out_sg[0].iov_base;
-
-        memcpy(&pdu->size, ptr, 4);
-        pdu->id = ptr[4];
-        memcpy(&pdu->tag, ptr + 5, 2);
-
-        submit_pdu(s, pdu);
-    }
-
-    free_pdu(s, pdu);
-}
-
-static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
-{
-    features |= 1 << VIRTIO_9P_MOUNT_TAG;
-    return features;
-}
-
-static V9fsState *to_virtio_9p(VirtIODevice *vdev)
-{
-    return (V9fsState *)vdev;
-}
-
-static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
-{
-    struct virtio_9p_config *cfg;
-    V9fsState *s = to_virtio_9p(vdev);
-
-    cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
-                        s->tag_len);
-    stw_raw(&cfg->tag_len, s->tag_len);
-    memcpy(cfg->tag, s->tag, s->tag_len);
-    memcpy(config, cfg, s->config_size);
-    qemu_free(cfg);
-}
-
-VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
- {
-    V9fsState *s;
-    int i, len;
-    struct stat stat;
-    FsTypeEntry *fse;
-
-
-    s = (V9fsState *)virtio_common_init("virtio-9p",
-                                    VIRTIO_ID_9P,
-                                    sizeof(struct virtio_9p_config)+
-                                    MAX_TAG_LEN,
-                                    sizeof(V9fsState));
-
-    /* initialize pdu allocator */
-    QLIST_INIT(&s->free_list);
-    for (i = 0; i < (MAX_REQ - 1); i++) {
-       QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
-    }
-
-    s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
-
-    fse = get_fsdev_fsentry(conf->fsdev_id);
-
-    if (!fse) {
-        /* We don't have a fsdev identified by fsdev_id */
-        fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
-                "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
-        exit(1);
-    }
-
-    if (!fse->path || !conf->tag) {
-        /* we haven't specified a mount_tag or the path */
-        fprintf(stderr, "fsdev with id %s needs path "
-                "and Virtio-9p device needs mount_tag arguments\n",
-                conf->fsdev_id);
-        exit(1);
-    }
-
-    if (!strcmp(fse->security_model, "passthrough")) {
-        /* Files on the Fileserver set to client user credentials */
-        s->ctx.fs_sm = SM_PASSTHROUGH;
-        s->ctx.xops = passthrough_xattr_ops;
-    } else if (!strcmp(fse->security_model, "mapped")) {
-        /* Files on the fileserver are set to QEMU credentials.
-         * Client user credentials are saved in extended attributes.
-         */
-        s->ctx.fs_sm = SM_MAPPED;
-        s->ctx.xops = mapped_xattr_ops;
-    } else if (!strcmp(fse->security_model, "none")) {
-        /*
-         * Files on the fileserver are set to QEMU credentials.
-         */
-        s->ctx.fs_sm = SM_NONE;
-        s->ctx.xops = none_xattr_ops;
-    } else {
-        fprintf(stderr, "Default to security_model=none. You may want"
-                " enable advanced security model using "
-                "security option:\n\t security_model=passthrough \n\t "
-                "security_model=mapped\n");
-        s->ctx.fs_sm = SM_NONE;
-        s->ctx.xops = none_xattr_ops;
-    }
-
-    if (lstat(fse->path, &stat)) {
-        fprintf(stderr, "share path %s does not exist\n", fse->path);
-        exit(1);
-    } else if (!S_ISDIR(stat.st_mode)) {
-        fprintf(stderr, "share path %s is not a directory \n", fse->path);
-        exit(1);
-    }
-
-    s->ctx.fs_root = qemu_strdup(fse->path);
-    len = strlen(conf->tag);
-    if (len > MAX_TAG_LEN) {
-        len = MAX_TAG_LEN;
-    }
-    /* s->tag is non-NULL terminated string */
-    s->tag = qemu_malloc(len);
-    memcpy(s->tag, conf->tag, len);
-    s->tag_len = len;
-    s->ctx.uid = -1;
-
-    s->ops = fse->ops;
-    s->vdev.get_features = virtio_9p_get_features;
-    s->config_size = sizeof(struct virtio_9p_config) +
-                        s->tag_len;
-    s->vdev.get_config = virtio_9p_get_config;
-
-    return &s->vdev;
-}
diff --git a/hw/virtio-9p.h b/hw/virtio-9p.h
deleted file mode 100644 (file)
index 2ae4ce7..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-#ifndef _QEMU_VIRTIO_9P_H
-#define _QEMU_VIRTIO_9P_H
-
-#include <sys/types.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <utime.h>
-
-#include "file-op-9p.h"
-
-/* The feature bitmap for virtio 9P */
-/* The mount point is specified in a config variable */
-#define VIRTIO_9P_MOUNT_TAG 0
-
-enum {
-    P9_TLERROR = 6,
-    P9_RLERROR,
-    P9_TSTATFS = 8,
-    P9_RSTATFS,
-    P9_TLOPEN = 12,
-    P9_RLOPEN,
-    P9_TLCREATE = 14,
-    P9_RLCREATE,
-    P9_TSYMLINK = 16,
-    P9_RSYMLINK,
-    P9_TMKNOD = 18,
-    P9_RMKNOD,
-    P9_TRENAME = 20,
-    P9_RRENAME,
-    P9_TREADLINK = 22,
-    P9_RREADLINK,
-    P9_TGETATTR = 24,
-    P9_RGETATTR,
-    P9_TSETATTR = 26,
-    P9_RSETATTR,
-    P9_TXATTRWALK = 30,
-    P9_RXATTRWALK,
-    P9_TXATTRCREATE = 32,
-    P9_RXATTRCREATE,
-    P9_TREADDIR = 40,
-    P9_RREADDIR,
-    P9_TFSYNC = 50,
-    P9_RFSYNC,
-    P9_TLOCK = 52,
-    P9_RLOCK,
-    P9_TGETLOCK = 54,
-    P9_RGETLOCK,
-    P9_TLINK = 70,
-    P9_RLINK,
-    P9_TMKDIR = 72,
-    P9_RMKDIR,
-    P9_TVERSION = 100,
-    P9_RVERSION,
-    P9_TAUTH = 102,
-    P9_RAUTH,
-    P9_TATTACH = 104,
-    P9_RATTACH,
-    P9_TERROR = 106,
-    P9_RERROR,
-    P9_TFLUSH = 108,
-    P9_RFLUSH,
-    P9_TWALK = 110,
-    P9_RWALK,
-    P9_TOPEN = 112,
-    P9_ROPEN,
-    P9_TCREATE = 114,
-    P9_RCREATE,
-    P9_TREAD = 116,
-    P9_RREAD,
-    P9_TWRITE = 118,
-    P9_RWRITE,
-    P9_TCLUNK = 120,
-    P9_RCLUNK,
-    P9_TREMOVE = 122,
-    P9_RREMOVE,
-    P9_TSTAT = 124,
-    P9_RSTAT,
-    P9_TWSTAT = 126,
-    P9_RWSTAT,
-};
-
-
-/* qid.types */
-enum {
-    P9_QTDIR = 0x80,
-    P9_QTAPPEND = 0x40,
-    P9_QTEXCL = 0x20,
-    P9_QTMOUNT = 0x10,
-    P9_QTAUTH = 0x08,
-    P9_QTTMP = 0x04,
-    P9_QTSYMLINK = 0x02,
-    P9_QTLINK = 0x01,
-    P9_QTFILE = 0x00,
-};
-
-enum p9_proto_version {
-    V9FS_PROTO_2000U = 0x01,
-    V9FS_PROTO_2000L = 0x02,
-};
-
-#define P9_NOTAG    (u16)(~0)
-#define P9_NOFID    (u32)(~0)
-#define P9_MAXWELEM 16
-
-/*
- * ample room for Twrite/Rread header
- * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4]
- */
-#define P9_IOHDRSZ 24
-
-typedef struct V9fsPDU V9fsPDU;
-
-struct V9fsPDU
-{
-    uint32_t size;
-    uint16_t tag;
-    uint8_t id;
-    VirtQueueElement elem;
-    QLIST_ENTRY(V9fsPDU) next;
-};
-
-
-/* FIXME
- * 1) change user needs to set groups and stuff
- */
-
-/* from Linux's linux/virtio_9p.h */
-
-/* The ID for virtio console */
-#define VIRTIO_ID_9P    9
-#define MAX_REQ         128
-#define MAX_TAG_LEN     32
-
-#define BUG_ON(cond) assert(!(cond))
-
-typedef struct V9fsFidState V9fsFidState;
-
-typedef struct V9fsString
-{
-    int16_t size;
-    char *data;
-} V9fsString;
-
-typedef struct V9fsQID
-{
-    int8_t type;
-    int32_t version;
-    int64_t path;
-} V9fsQID;
-
-typedef struct V9fsStat
-{
-    int16_t size;
-    int16_t type;
-    int32_t dev;
-    V9fsQID qid;
-    int32_t mode;
-    int32_t atime;
-    int32_t mtime;
-    int64_t length;
-    V9fsString name;
-    V9fsString uid;
-    V9fsString gid;
-    V9fsString muid;
-    /* 9p2000.u */
-    V9fsString extension;
-   int32_t n_uid;
-    int32_t n_gid;
-    int32_t n_muid;
-} V9fsStat;
-
-enum {
-    P9_FID_NONE = 0,
-    P9_FID_FILE,
-    P9_FID_DIR,
-    P9_FID_XATTR,
-};
-
-typedef struct V9fsXattr
-{
-    int64_t copied_len;
-    int64_t len;
-    void *value;
-    V9fsString name;
-    int flags;
-} V9fsXattr;
-
-struct V9fsFidState
-{
-    int fid_type;
-    int32_t fid;
-    V9fsString path;
-    union {
-       int fd;
-       DIR *dir;
-       V9fsXattr xattr;
-    } fs;
-    uid_t uid;
-    V9fsFidState *next;
-};
-
-typedef struct V9fsState
-{
-    VirtIODevice vdev;
-    VirtQueue *vq;
-    V9fsPDU pdus[MAX_REQ];
-    QLIST_HEAD(, V9fsPDU) free_list;
-    V9fsFidState *fid_list;
-    FileOperations *ops;
-    FsContext ctx;
-    uint16_t tag_len;
-    uint8_t *tag;
-    size_t config_size;
-    enum p9_proto_version proto_version;
-    int32_t msize;
-} V9fsState;
-
-typedef struct V9fsCreateState {
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsFidState *fidp;
-    V9fsQID qid;
-    int32_t perm;
-    int8_t mode;
-    struct stat stbuf;
-    V9fsString name;
-    V9fsString extension;
-    V9fsString fullname;
-    int iounit;
-} V9fsCreateState;
-
-typedef struct V9fsLcreateState {
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsFidState *fidp;
-    V9fsQID qid;
-    int32_t iounit;
-    struct stat stbuf;
-    V9fsString name;
-    V9fsString fullname;
-} V9fsLcreateState;
-
-typedef struct V9fsStatState {
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsStat v9stat;
-    V9fsFidState *fidp;
-    struct stat stbuf;
-} V9fsStatState;
-
-typedef struct V9fsStatDotl {
-    uint64_t st_result_mask;
-    V9fsQID qid;
-    uint32_t st_mode;
-    uint32_t st_uid;
-    uint32_t st_gid;
-    uint64_t st_nlink;
-    uint64_t st_rdev;
-    uint64_t st_size;
-    uint64_t st_blksize;
-    uint64_t st_blocks;
-    uint64_t st_atime_sec;
-    uint64_t st_atime_nsec;
-    uint64_t st_mtime_sec;
-    uint64_t st_mtime_nsec;
-    uint64_t st_ctime_sec;
-    uint64_t st_ctime_nsec;
-    uint64_t st_btime_sec;
-    uint64_t st_btime_nsec;
-    uint64_t st_gen;
-    uint64_t st_data_version;
-} V9fsStatDotl;
-
-typedef struct V9fsStatStateDotl {
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsStatDotl v9stat_dotl;
-    struct stat stbuf;
-} V9fsStatStateDotl;
-
-
-typedef struct V9fsWalkState {
-    V9fsPDU *pdu;
-    size_t offset;
-    int16_t nwnames;
-    int name_idx;
-    V9fsQID *qids;
-    V9fsFidState *fidp;
-    V9fsFidState *newfidp;
-    V9fsString path;
-    V9fsString *wnames;
-    struct stat stbuf;
-} V9fsWalkState;
-
-typedef struct V9fsOpenState {
-    V9fsPDU *pdu;
-    size_t offset;
-    int32_t mode;
-    V9fsFidState *fidp;
-    V9fsQID qid;
-    struct stat stbuf;
-    int iounit;
-} V9fsOpenState;
-
-typedef struct V9fsReadState {
-    V9fsPDU *pdu;
-    size_t offset;
-    int32_t count;
-    int32_t total;
-    int64_t off;
-    V9fsFidState *fidp;
-    struct iovec iov[128]; /* FIXME: bad, bad, bad */
-    struct iovec *sg;
-    off_t dir_pos;
-    struct dirent *dent;
-    struct stat stbuf;
-    V9fsString name;
-    V9fsStat v9stat;
-    int32_t len;
-    int32_t cnt;
-    int32_t max_count;
-} V9fsReadState;
-
-typedef struct V9fsWriteState {
-    V9fsPDU *pdu;
-    size_t offset;
-    int32_t len;
-    int32_t count;
-    int32_t total;
-    int64_t off;
-    V9fsFidState *fidp;
-    struct iovec iov[128]; /* FIXME: bad, bad, bad */
-    struct iovec *sg;
-    int cnt;
-} V9fsWriteState;
-
-typedef struct V9fsRemoveState {
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsFidState *fidp;
-} V9fsRemoveState;
-
-typedef struct V9fsWstatState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    int16_t unused;
-    V9fsStat v9stat;
-    V9fsFidState *fidp;
-    struct stat stbuf;
-} V9fsWstatState;
-
-typedef struct V9fsSymlinkState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsString name;
-    V9fsString symname;
-    V9fsString fullname;
-    V9fsFidState *dfidp;
-    V9fsQID qid;
-    struct stat stbuf;
-} V9fsSymlinkState;
-
-typedef struct V9fsIattr
-{
-    int32_t valid;
-    int32_t mode;
-    int32_t uid;
-    int32_t gid;
-    int64_t size;
-    int64_t atime_sec;
-    int64_t atime_nsec;
-    int64_t mtime_sec;
-    int64_t mtime_nsec;
-} V9fsIattr;
-
-typedef struct V9fsSetattrState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsIattr v9iattr;
-    V9fsFidState *fidp;
-} V9fsSetattrState;
-
-struct virtio_9p_config
-{
-    /* number of characters in tag */
-    uint16_t tag_len;
-    /* Variable size tag name */
-    uint8_t tag[0];
-} __attribute__((packed));
-
-typedef struct V9fsStatfs
-{
-    uint32_t f_type;
-    uint32_t f_bsize;
-    uint64_t f_blocks;
-    uint64_t f_bfree;
-    uint64_t f_bavail;
-    uint64_t f_files;
-    uint64_t f_ffree;
-    uint64_t fsid_val;
-    uint32_t f_namelen;
-} V9fsStatfs;
-
-typedef struct V9fsStatfsState {
-    V9fsPDU *pdu;
-    size_t offset;
-    int32_t fid;
-    V9fsStatfs v9statfs;
-    V9fsFidState *fidp;
-    struct statfs stbuf;
-} V9fsStatfsState;
-
-typedef struct V9fsMkState {
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsQID qid;
-    struct stat stbuf;
-    V9fsString name;
-    V9fsString fullname;
-} V9fsMkState;
-
-typedef struct V9fsRenameState {
-    V9fsPDU *pdu;
-    V9fsFidState *fidp;
-    size_t offset;
-    int32_t newdirfid;
-    V9fsString name;
-} V9fsRenameState;
-
-typedef struct V9fsXattrState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsFidState *file_fidp;
-    V9fsFidState *xattr_fidp;
-    V9fsString name;
-    int64_t size;
-    int flags;
-    void *value;
-} V9fsXattrState;
-
-#define P9_LOCK_SUCCESS 0
-#define P9_LOCK_BLOCKED 1
-#define P9_LOCK_ERROR 2
-#define P9_LOCK_GRACE 3
-
-#define P9_LOCK_FLAGS_BLOCK 1
-#define P9_LOCK_FLAGS_RECLAIM 2
-
-typedef struct V9fsFlock
-{
-    uint8_t type;
-    uint32_t flags;
-    uint64_t start; /* absolute offset */
-    uint64_t length;
-    uint32_t proc_id;
-    V9fsString client_id;
-} V9fsFlock;
-
-typedef struct V9fsLockState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    int8_t status;
-    struct stat stbuf;
-    V9fsFidState *fidp;
-    V9fsFlock *flock;
-} V9fsLockState;
-
-typedef struct V9fsGetlock
-{
-    uint8_t type;
-    uint64_t start; /* absolute offset */
-    uint64_t length;
-    uint32_t proc_id;
-    V9fsString client_id;
-} V9fsGetlock;
-
-typedef struct V9fsGetlockState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    struct stat stbuf;
-    V9fsFidState *fidp;
-    V9fsGetlock *glock;
-} V9fsGetlockState;
-
-typedef struct V9fsReadLinkState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsString target;
-} V9fsReadLinkState;
-
-size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
-                      size_t offset, size_t size, int pack);
-
-static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
-                        size_t offset, size_t size)
-{
-    return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
-}
-
-#endif
index 8adddeaa5335e9801b2157c0286ef31a357fa17f..70a87103439ac0205eedb88b244ca9d3aa759174 100644 (file)
@@ -15,7 +15,6 @@
 #include "qemu-common.h"
 #include "virtio.h"
 #include "pc.h"
-#include "sysemu.h"
 #include "cpu.h"
 #include "monitor.h"
 #include "balloon.h"
@@ -191,7 +190,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
     VirtIOBalloon *dev = to_virtio_balloon(vdev);
     struct virtio_balloon_config config;
     memcpy(&config, config_data, 8);
-    dev->actual = config.actual;
+    dev->actual = le32_to_cpu(config.actual);
 }
 
 static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
index b14fb995e81994c54431599fd5fd2e32c71e11aa..91e0394af9f535a02cd6ead94f03324b4fa0409e 100644 (file)
@@ -290,6 +290,10 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
         virtio_blk_rw_complete(req, -EIO);
         return;
     }
+    if (req->qiov.size % req->dev->conf->logical_block_size) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
 
     if (mrb->num_writes == 32) {
         virtio_submit_multiwrite(req->dev->bs, mrb);
@@ -317,6 +321,10 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
         virtio_blk_rw_complete(req, -EIO);
         return;
     }
+    if (req->qiov.size % req->dev->conf->logical_block_size) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
 
     acb = bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
                          req->qiov.size / BDRV_SECTOR_SIZE,
index 6b5237b3ce3e15ea41a5e746415c78dd671199d7..de539c4eacfb252c6d738998f8c838094a01965f 100644 (file)
@@ -28,6 +28,22 @@ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
     return qemu_chr_write(vcon->chr, buf, len);
 }
 
+/* Callback function that's called when the guest opens the port */
+static void guest_open(VirtIOSerialPort *port)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+
+    qemu_chr_guest_open(vcon->chr);
+}
+
+/* Callback function that's called when the guest closes the port */
+static void guest_close(VirtIOSerialPort *port)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+
+    qemu_chr_guest_close(vcon->chr);
+}
+
 /* Readiness of the guest to accept data on a port */
 static int chr_can_read(void *opaque)
 {
@@ -64,6 +80,8 @@ static int generic_port_init(VirtConsole *vcon, VirtIOSerialPort *port)
         qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
                               vcon);
         vcon->port.info->have_data = flush_buf;
+        vcon->port.info->guest_open = guest_open;
+        vcon->port.info->guest_close = guest_close;
     }
     return 0;
 }
index df10703b294fe45989b7b35acab7f158ed9d0dc6..c19629d5073e43d15f7fc722738fee8dd00521f9 100644 (file)
@@ -873,10 +873,11 @@ static PCIDeviceInfo virtio_info[] = {
         .qdev.reset = virtio_pci_reset,
     },{
         .qdev.name  = "virtio-net-pci",
+        .qdev.alias = "virtio-net",
         .qdev.size  = sizeof(VirtIOPCIProxy),
         .init       = virtio_net_init_pci,
         .exit       = virtio_net_exit_pci,
-        .romfile    = "pxe-virtio.bin",
+        .romfile    = "pxe-virtio.rom",
         .qdev.props = (Property[]) {
             DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
                             VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
@@ -911,6 +912,7 @@ static PCIDeviceInfo virtio_info[] = {
         .qdev.reset = virtio_pci_reset,
     },{
         .qdev.name = "virtio-balloon-pci",
+        .qdev.alias = "virtio-balloon",
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_balloon_init_pci,
         .exit      = virtio_exit_pci,
@@ -922,6 +924,7 @@ static PCIDeviceInfo virtio_info[] = {
     },{
 #ifdef CONFIG_VIRTFS
         .qdev.name = "virtio-9p-pci",
+        .qdev.alias = "virtio-9p",
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_9p_init_pci,
         .qdev.props = (Property[]) {
index 62273799b6cfaa1b6ab781dd63b05a546467cba1..f10d48fdb023f5916f0992f4d2c9d75e8cd9742b 100644 (file)
@@ -494,7 +494,7 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
     VirtIOSerial *s = opaque;
     VirtIOSerialPort *port;
     uint32_t nr_active_ports;
-    unsigned int i;
+    unsigned int i, max_nr_ports;
 
     /* The virtio device */
     virtio_save(&s->vdev, f);
@@ -506,8 +506,8 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
     qemu_put_be32s(f, &s->config.max_nr_ports);
 
     /* The ports map */
-
-    for (i = 0; i < (s->config.max_nr_ports + 31) / 32; i++) {
+    max_nr_ports = tswap32(s->config.max_nr_ports);
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
         qemu_put_be32s(f, &s->ports_map[i]);
     }
 
@@ -568,7 +568,8 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
     qemu_get_be16s(f, &s->config.rows);
 
     qemu_get_be32s(f, &max_nr_ports);
-    if (max_nr_ports > s->config.max_nr_ports) {
+    tswap32s(&max_nr_ports);
+    if (max_nr_ports > tswap32(s->config.max_nr_ports)) {
         /* Source could have had more ports than us. Fail migration. */
         return -EINVAL;
     }
@@ -670,9 +671,10 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
 /* This function is only used if a port id is not provided by the user */
 static uint32_t find_free_port_id(VirtIOSerial *vser)
 {
-    unsigned int i;
+    unsigned int i, max_nr_ports;
 
-    for (i = 0; i < (vser->config.max_nr_ports + 31) / 32; i++) {
+    max_nr_ports = tswap32(vser->config.max_nr_ports);
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
         uint32_t map, bit;
 
         map = vser->ports_map[i];
@@ -720,7 +722,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
     VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
     VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
-    int ret;
+    int ret, max_nr_ports;
     bool plugging_port0;
 
     port->vser = bus->vser;
@@ -750,9 +752,10 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
         }
     }
 
-    if (port->id >= port->vser->config.max_nr_ports) {
+    max_nr_ports = tswap32(port->vser->config.max_nr_ports);
+    if (port->id >= max_nr_ports) {
         error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u\n",
-                     port->vser->config.max_nr_ports - 1);
+                     max_nr_ports - 1);
         return -1;
     }
 
@@ -863,7 +866,7 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
         vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
     }
 
-    vser->config.max_nr_ports = conf->max_virtserial_ports;
+    vser->config.max_nr_ports = tswap32(conf->max_virtserial_ports);
     vser->ports_map = qemu_mallocz(((conf->max_virtserial_ports + 31) / 32)
         * sizeof(vser->ports_map[0]));
     /*
index 31bd9e32dc5abd890fea27ecb23c9616df027311..6e8814cb6447da3dbe590f523864bfbec5c21874 100644 (file)
@@ -16,7 +16,6 @@
 #include "trace.h"
 #include "qemu-error.h"
 #include "virtio.h"
-#include "sysemu.h"
 
 /* The alignment to use between consumer and producer parts of vring.
  * x86 pagesize again. */
index 19010e4843b563818d00d574085d87eb90791516..c8aefaabb82301d6e1ad054ae3fdf6102e45f505 100644 (file)
@@ -24,7 +24,6 @@
 #include "hw.h"
 #include "isa.h"
 #include "pc.h"
-#include "sysemu.h"
 #include "kvm.h"
 #include "qdev.h"
 
index 818460d716f35f4979b2549bbbc75359f2bbbcfe..ca8f826a07fc7e7bf49526b6e0c9464747962739 100644 (file)
@@ -156,12 +156,10 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address,
 
 typedef struct VT686PMState {
     PCIDevice dev;
-    uint16_t pmsts;
-    uint16_t pmen;
-    uint16_t pmcntrl;
+    ACPIPM1EVT pm1a;
+    ACPIPM1CNT pm1_cnt;
     APMState apm;
-    QEMUTimer *tmr_timer;
-    int64_t tmr_overflow_time;
+    ACPIPMTimer tmr;
     PMSMBus smb;
     uint32_t smb_io_base;
 } VT686PMState;
@@ -174,54 +172,25 @@ typedef struct VT686MC97State {
     PCIDevice dev;
 } VT686MC97State;
 
-#define RTC_EN    (1 << 10)
-#define PWRBTN_EN (1 << 8)
-#define GBL_EN    (1 << 5)
-#define TMROF_EN  (1 << 0)
-#define SUS_EN    (1 << 13)
-
-#define ACPI_ENABLE  0xf1
-#define ACPI_DISABLE 0xf0
-
-static uint32_t get_pmtmr(VT686PMState *s)
-{
-    uint32_t d;
-    d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec());
-    return d & 0xffffff;
-}
-
-static int get_pmsts(VT686PMState *s)
-{
-    int64_t d;
-    int pmsts;
-    pmsts = s->pmsts;
-    d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec());
-    if (d >= s->tmr_overflow_time)
-        s->pmsts |= TMROF_EN;
-    return pmsts;
-}
-
 static void pm_update_sci(VT686PMState *s)
 {
     int sci_level, pmsts;
-    int64_t expire_time;
 
-    pmsts = get_pmsts(s);
-    sci_level = (((pmsts & s->pmen) &
-                  (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
+    pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
+    sci_level = (((pmsts & s->pm1a.en) &
+                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
+                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
+                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
+                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
     qemu_set_irq(s->dev.irq[0], sci_level);
     /* schedule a timer interruption if needed */
-    if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
-        expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), PM_TIMER_FREQUENCY);
-        qemu_mod_timer(s->tmr_timer, expire_time);
-    } else {
-        qemu_del_timer(s->tmr_timer);
-    }
+    acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
+                       !(pmsts & ACPI_BITMASK_TIMER_STATUS));
 }
 
-static void pm_tmr_timer(void *opaque)
+static void pm_tmr_timer(ACPIPMTimer *tmr)
 {
-    VT686PMState *s = opaque;
+    VT686PMState *s = container_of(tmr, VT686PMState, tmr);
     pm_update_sci(s);
 }
 
@@ -232,39 +201,15 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
     addr &= 0x0f;
     switch (addr) {
     case 0x00:
-        {
-            int64_t d;
-            int pmsts;
-            pmsts = get_pmsts(s);
-            if (pmsts & val & TMROF_EN) {
-                /* if TMRSTS is reset, then compute the new overflow time */
-                d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec());
-                s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
-            }
-            s->pmsts &= ~val;
-            pm_update_sci(s);
-        }
+        acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val);
+        pm_update_sci(s);
         break;
     case 0x02:
-        s->pmen = val;
+        s->pm1a.en = val;
         pm_update_sci(s);
         break;
     case 0x04:
-        {
-            int sus_typ;
-            s->pmcntrl = val & ~(SUS_EN);
-            if (val & SUS_EN) {
-                /* change suspend type */
-                sus_typ = (val >> 10) & 3;
-                switch (sus_typ) {
-                case 0: /* soft power off */
-                    qemu_system_shutdown_request();
-                    break;
-                default:
-                    break;
-                }
-            }
-        }
+        acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val);
         break;
     default:
         break;
@@ -280,13 +225,13 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
     addr &= 0x0f;
     switch (addr) {
     case 0x00:
-        val = get_pmsts(s);
+        val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
         break;
     case 0x02:
-        val = s->pmen;
+        val = s->pm1a.en;
         break;
     case 0x04:
-        val = s->pmcntrl;
+        val = s->pm1_cnt.cnt;
         break;
     default:
         val = 0;
@@ -310,7 +255,7 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
     addr &= 0x0f;
     switch (addr) {
     case 0x08:
-        val = get_pmtmr(s);
+        val = acpi_pm_tmr_get(&s->tmr);
         break;
     default:
         val = 0;
@@ -361,12 +306,12 @@ static const VMStateDescription vmstate_acpi = {
     .post_load = vmstate_acpi_post_load,
     .fields      = (VMStateField []) {
         VMSTATE_PCI_DEVICE(dev, VT686PMState),
-        VMSTATE_UINT16(pmsts, VT686PMState),
-        VMSTATE_UINT16(pmen, VT686PMState),
-        VMSTATE_UINT16(pmcntrl, VT686PMState),
+        VMSTATE_UINT16(pm1a.sts, VT686PMState),
+        VMSTATE_UINT16(pm1a.en, VT686PMState),
+        VMSTATE_UINT16(pm1_cnt.cnt, VT686PMState),
         VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState),
-        VMSTATE_TIMER(tmr_timer, VT686PMState),
-        VMSTATE_INT64(tmr_overflow_time, VT686PMState),
+        VMSTATE_TIMER(tmr.timer, VT686PMState),
+        VMSTATE_INT64(tmr.overflow_time, VT686PMState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -486,7 +431,8 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
 
     apm_init(&s->apm, NULL, s);
 
-    s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s);
+    acpi_pm_tmr_init(&s->tmr, pm_tmr_timer);
+    acpi_pm1_cnt_init(&s->pm1_cnt, NULL);
 
     pm_smbus_init(&s->dev.qdev, &s->smb);
 
index d2261f4139252e0f56f4f71f18874e78f2057840..c6c81638135baa924722f9f7e0d5099a42bcfbad 100644 (file)
@@ -33,7 +33,6 @@
 #include <xenctrl.h>
 
 #include "hw.h"
-#include "sysemu.h"
 #include "qemu-char.h"
 #include "xen_backend.h"
 
index 445bf03aa0ef037f7509063a99054a636fc6a7e6..558bf8ae25d79f6d3bccbaffdf27b8c9f1525023 100644 (file)
@@ -310,7 +310,7 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
     off_t pos;
 
     if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
-       goto err;
+       goto err_no_map;
     if (ioreq->presync)
        bdrv_flush(blkdev->bs);
 
@@ -364,6 +364,9 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
     return 0;
 
 err:
+    ioreq_unmap(ioreq);
+err_no_map:
+    ioreq_finish(ioreq);
     ioreq->status = BLKIF_RSP_ERROR;
     return -1;
 }
@@ -393,7 +396,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
     struct XenBlkDev *blkdev = ioreq->blkdev;
 
     if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
-       goto err;
+       goto err_no_map;
 
     ioreq->aio_inflight++;
     if (ioreq->presync)
@@ -427,6 +430,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
     return 0;
 
 err:
+    ioreq_unmap(ioreq);
+err_no_map:
+    ioreq_finish(ioreq);
     ioreq->status = BLKIF_RSP_ERROR;
     return -1;
 }
index 371c56206da0260d9071b41c9eb932d47f868296..4093587df1549290f78e4791eb9d7a344c5b4b47 100644 (file)
@@ -1,7 +1,6 @@
 #include <signal.h>
 #include "xen_backend.h"
 #include "xen_domainbuild.h"
-#include "sysemu.h"
 #include "qemu-timer.h"
 #include "qemu-log.h"
 
index 77a34bf111dffedc9c95823b3c694e27d316bdee..0d7f73ed8261bad6c851fffc9c977a2b8c792b8b 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "hw.h"
 #include "pc.h"
-#include "sysemu.h"
 #include "boards.h"
 #include "xen_backend.h"
 #include "xen_domainbuild.h"
index da5297b4989952d188ee0c6f8359bdb9a5619a9d..1db75fbe49d13536e7e5ab76a02f5103c83e5786 100644 (file)
@@ -44,7 +44,6 @@
 #include <xen/io/protocols.h>
 
 #include "hw.h"
-#include "sysemu.h"
 #include "console.h"
 #include "qemu-char.h"
 #include "xen_backend.h"
diff --git a/hw/xics.c b/hw/xics.c
new file mode 100644 (file)
index 0000000..13a1d25
--- /dev/null
+++ b/hw/xics.c
@@ -0,0 +1,496 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "hw.h"
+#include "hw/spapr.h"
+#include "hw/xics.h"
+
+#include <pthread.h>
+
+/*
+ * ICP: Presentation layer
+ */
+
+struct icp_server_state {
+    uint32_t xirr;
+    uint8_t pending_priority;
+    uint8_t mfrr;
+    qemu_irq output;
+};
+
+#define XISR_MASK  0x00ffffff
+#define CPPR_MASK  0xff000000
+
+#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
+#define CPPR(ss)   (((ss)->xirr) >> 24)
+
+struct ics_state;
+
+struct icp_state {
+    long nr_servers;
+    struct icp_server_state *ss;
+    struct ics_state *ics;
+};
+
+static void ics_reject(struct ics_state *ics, int nr);
+static void ics_resend(struct ics_state *ics);
+static void ics_eoi(struct ics_state *ics, int nr);
+
+static void icp_check_ipi(struct icp_state *icp, int server)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
+        return;
+    }
+
+    if (XISR(ss)) {
+        ics_reject(icp->ics, XISR(ss));
+    }
+
+    ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
+    ss->pending_priority = ss->mfrr;
+    qemu_irq_raise(ss->output);
+}
+
+static void icp_resend(struct icp_state *icp, int server)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if (ss->mfrr < CPPR(ss)) {
+        icp_check_ipi(icp, server);
+    }
+    ics_resend(icp->ics);
+}
+
+static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+    uint8_t old_cppr;
+    uint32_t old_xisr;
+
+    old_cppr = CPPR(ss);
+    ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
+
+    if (cppr < old_cppr) {
+        if (XISR(ss) && (cppr <= ss->pending_priority)) {
+            old_xisr = XISR(ss);
+            ss->xirr &= ~XISR_MASK; /* Clear XISR */
+            qemu_irq_lower(ss->output);
+            ics_reject(icp->ics, old_xisr);
+        }
+    } else {
+        if (!XISR(ss)) {
+            icp_resend(icp, server);
+        }
+    }
+}
+
+static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr)
+{
+    struct icp_server_state *ss = icp->ss + nr;
+
+    ss->mfrr = mfrr;
+    if (mfrr < CPPR(ss)) {
+        icp_check_ipi(icp, nr);
+    }
+}
+
+static uint32_t icp_accept(struct icp_server_state *ss)
+{
+    uint32_t xirr;
+
+    qemu_irq_lower(ss->output);
+    xirr = ss->xirr;
+    ss->xirr = ss->pending_priority << 24;
+    return xirr;
+}
+
+static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    ics_eoi(icp->ics, xirr & XISR_MASK);
+    /* Send EOI -> ICS */
+    ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
+    if (!XISR(ss)) {
+        icp_resend(icp, server);
+    }
+}
+
+static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if ((priority >= CPPR(ss))
+        || (XISR(ss) && (ss->pending_priority <= priority))) {
+        ics_reject(icp->ics, nr);
+    } else {
+        if (XISR(ss)) {
+            ics_reject(icp->ics, XISR(ss));
+        }
+        ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
+        ss->pending_priority = priority;
+        qemu_irq_raise(ss->output);
+    }
+}
+
+/*
+ * ICS: Source layer
+ */
+
+struct ics_irq_state {
+    int server;
+    uint8_t priority;
+    uint8_t saved_priority;
+    /* int pending:1; */
+    /* int presented:1; */
+    int rejected:1;
+    int masked_pending:1;
+};
+
+struct ics_state {
+    int nr_irqs;
+    int offset;
+    qemu_irq *qirqs;
+    struct ics_irq_state *irqs;
+    struct icp_state *icp;
+};
+
+static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
+{
+    return (nr >= ics->offset)
+        && (nr < (ics->offset + ics->nr_irqs));
+}
+
+static void ics_set_irq_msi(void *opaque, int nr, int val)
+{
+    struct ics_state *ics = (struct ics_state *)opaque;
+    struct ics_irq_state *irq = ics->irqs + nr;
+
+    if (val) {
+        if (irq->priority == 0xff) {
+            irq->masked_pending = 1;
+            /* masked pending */ ;
+        } else  {
+            icp_irq(ics->icp, irq->server, nr + ics->offset, irq->priority);
+        }
+    }
+}
+
+static void ics_reject_msi(struct ics_state *ics, int nr)
+{
+    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+    irq->rejected = 1;
+}
+
+static void ics_resend_msi(struct ics_state *ics)
+{
+    int i;
+
+    for (i = 0; i < ics->nr_irqs; i++) {
+        struct ics_irq_state *irq = ics->irqs + i;
+
+        /* FIXME: filter by server#? */
+        if (irq->rejected) {
+            irq->rejected = 0;
+            if (irq->priority != 0xff) {
+                icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
+            }
+        }
+    }
+}
+
+static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
+                               uint8_t priority)
+{
+    struct ics_irq_state *irq = ics->irqs + nr;
+
+    irq->server = server;
+    irq->priority = priority;
+
+    if (!irq->masked_pending || (priority == 0xff)) {
+        return;
+    }
+
+    irq->masked_pending = 0;
+    icp_irq(ics->icp, server, nr + ics->offset, priority);
+}
+
+static void ics_reject(struct ics_state *ics, int nr)
+{
+    ics_reject_msi(ics, nr);
+}
+
+static void ics_resend(struct ics_state *ics)
+{
+    ics_resend_msi(ics);
+}
+
+static void ics_eoi(struct ics_state *ics, int nr)
+{
+}
+
+/*
+ * Exported functions
+ */
+
+qemu_irq xics_find_qirq(struct icp_state *icp, int irq)
+{
+    if ((irq < icp->ics->offset)
+        || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
+        return NULL;
+    }
+
+    return icp->ics->qirqs[irq - icp->ics->offset];
+}
+
+static target_ulong h_cppr(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    target_ulong cppr = args[0];
+
+    icp_set_cppr(spapr->icp, env->cpu_index, cppr);
+    return H_SUCCESS;
+}
+
+static target_ulong h_ipi(CPUState *env, sPAPREnvironment *spapr,
+                          target_ulong opcode, target_ulong *args)
+{
+    target_ulong server = args[0];
+    target_ulong mfrr = args[1];
+
+    if (server >= spapr->icp->nr_servers) {
+        return H_PARAMETER;
+    }
+
+    icp_set_mfrr(spapr->icp, server, mfrr);
+    return H_SUCCESS;
+
+}
+
+static target_ulong h_xirr(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index);
+
+    args[0] = xirr;
+    return H_SUCCESS;
+}
+
+static target_ulong h_eoi(CPUState *env, sPAPREnvironment *spapr,
+                          target_ulong opcode, target_ulong *args)
+{
+    target_ulong xirr = args[0];
+
+    icp_eoi(spapr->icp, env->cpu_index, xirr);
+    return H_SUCCESS;
+}
+
+static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
+                          uint32_t nargs, target_ulong args,
+                          uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr, server, priority;
+
+    if ((nargs != 3) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+    server = rtas_ld(args, 1);
+    priority = rtas_ld(args, 2);
+
+    if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
+        || (priority > 0xff)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    ics_write_xive_msi(ics, nr - ics->offset, server, priority);
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token,
+                          uint32_t nargs, target_ulong args,
+                          uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 3)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    rtas_st(rets, 0, 0); /* Success */
+    rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
+    rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
+}
+
+static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    /* This is a NOP for now, since the described PAPR semantics don't
+     * seem to gel with what Linux does */
+#if 0
+    struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
+
+    irq->saved_priority = irq->priority;
+    ics_write_xive_msi(xics, nr - xics->offset, irq->server, 0xff);
+#endif
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,
+                        uint32_t nargs, target_ulong args,
+                        uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    /* This is a NOP for now, since the described PAPR semantics don't
+     * seem to gel with what Linux does */
+#if 0
+    struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
+
+    ics_write_xive_msi(xics, nr - xics->offset,
+                       irq->server, irq->saved_priority);
+#endif
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+struct icp_state *xics_system_init(int nr_irqs)
+{
+    CPUState *env;
+    int max_server_num;
+    int i;
+    struct icp_state *icp;
+    struct ics_state *ics;
+
+    max_server_num = -1;
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (env->cpu_index > max_server_num) {
+            max_server_num = env->cpu_index;
+        }
+    }
+
+    icp = qemu_mallocz(sizeof(*icp));
+    icp->nr_servers = max_server_num + 1;
+    icp->ss = qemu_mallocz(icp->nr_servers*sizeof(struct icp_server_state));
+
+    for (i = 0; i < icp->nr_servers; i++) {
+        icp->ss[i].mfrr = 0xff;
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        struct icp_server_state *ss = &icp->ss[env->cpu_index];
+
+        switch (PPC_INPUT(env)) {
+        case PPC_FLAGS_INPUT_POWER7:
+            ss->output = env->irq_inputs[POWER7_INPUT_INT];
+            break;
+
+        case PPC_FLAGS_INPUT_970:
+            ss->output = env->irq_inputs[PPC970_INPUT_INT];
+            break;
+
+        default:
+            hw_error("XICS interrupt model does not support this CPU bus "
+                     "model\n");
+            exit(1);
+        }
+    }
+
+    ics = qemu_mallocz(sizeof(*ics));
+    ics->nr_irqs = nr_irqs;
+    ics->offset = 16;
+    ics->irqs = qemu_mallocz(nr_irqs * sizeof(struct ics_irq_state));
+
+    icp->ics = ics;
+    ics->icp = icp;
+
+    for (i = 0; i < nr_irqs; i++) {
+        ics->irqs[i].priority = 0xff;
+        ics->irqs[i].saved_priority = 0xff;
+    }
+
+    ics->qirqs = qemu_allocate_irqs(ics_set_irq_msi, ics, nr_irqs);
+
+    spapr_register_hypercall(H_CPPR, h_cppr);
+    spapr_register_hypercall(H_IPI, h_ipi);
+    spapr_register_hypercall(H_XIRR, h_xirr);
+    spapr_register_hypercall(H_EOI, h_eoi);
+
+    spapr_rtas_register("ibm,set-xive", rtas_set_xive);
+    spapr_rtas_register("ibm,get-xive", rtas_get_xive);
+    spapr_rtas_register("ibm,int-off", rtas_int_off);
+    spapr_rtas_register("ibm,int-on", rtas_int_on);
+
+    return icp;
+}
diff --git a/hw/xics.h b/hw/xics.h
new file mode 100644 (file)
index 0000000..83c1182
--- /dev/null
+++ b/hw/xics.h
@@ -0,0 +1,38 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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.
+ *
+ */
+#if !defined(__XICS_H__)
+#define __XICS_H__
+
+#define XICS_IPI        0x2
+
+struct icp_state;
+
+qemu_irq xics_find_qirq(struct icp_state *icp, int irq);
+
+struct icp_state *xics_system_init(int nr_irqs);
+
+#endif /* __XICS_H__ */
index 30827b03cd0e869eb3d62a7ae2e6782cb7398fff..d398c18e9e137ef2fbddb384faa50a4a97b56f34 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include "sysbus.h"
-#include "sysemu.h"
 #include "qemu-timer.h"
 
 #define D(x)
diff --git a/input.c b/input.c
index ec05548f7a75f961d7ef22cf59250f0cf6f78f3e..5664d3a1e3e009dadf07eede7ef2bc8abcc43973 100644 (file)
--- a/input.c
+++ b/input.c
@@ -161,15 +161,15 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
 
     if (mouse_event) {
         if (graphic_rotate) {
-            if (entry->qemu_put_mouse_event_absolute)
+            if (entry->qemu_put_mouse_event_absolute) {
                 width = 0x7fff;
-            else
+            } else {
                 width = graphic_width - 1;
-            mouse_event(mouse_event_opaque,
-                        width - dy, dx, dz, buttons_state);
-        } else
-            mouse_event(mouse_event_opaque,
-                        dx, dy, dz, buttons_state);
+            }
+            mouse_event(mouse_event_opaque, width - dy, dx, dz, buttons_state);
+        } else {
+            mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state);
+        }
     }
 }
 
diff --git a/iohandler.c b/iohandler.c
new file mode 100644 (file)
index 0000000..2b82421
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * QEMU System Emulator - managing I/O handler
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config-host.h"
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "qemu-queue.h"
+
+#ifndef _WIN32
+#include <sys/wait.h>
+#endif
+
+typedef struct IOHandlerRecord {
+    int fd;
+    IOCanReadHandler *fd_read_poll;
+    IOHandler *fd_read;
+    IOHandler *fd_write;
+    int deleted;
+    void *opaque;
+    QLIST_ENTRY(IOHandlerRecord) next;
+} IOHandlerRecord;
+
+static QLIST_HEAD(, IOHandlerRecord) io_handlers =
+    QLIST_HEAD_INITIALIZER(io_handlers);
+
+
+/* XXX: fd_read_poll should be suppressed, but an API change is
+   necessary in the character devices to suppress fd_can_read(). */
+int qemu_set_fd_handler2(int fd,
+                         IOCanReadHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque)
+{
+    IOHandlerRecord *ioh;
+
+    if (!fd_read && !fd_write) {
+        QLIST_FOREACH(ioh, &io_handlers, next) {
+            if (ioh->fd == fd) {
+                ioh->deleted = 1;
+                break;
+            }
+        }
+    } else {
+        QLIST_FOREACH(ioh, &io_handlers, next) {
+            if (ioh->fd == fd)
+                goto found;
+        }
+        ioh = qemu_mallocz(sizeof(IOHandlerRecord));
+        QLIST_INSERT_HEAD(&io_handlers, ioh, next);
+    found:
+        ioh->fd = fd;
+        ioh->fd_read_poll = fd_read_poll;
+        ioh->fd_read = fd_read;
+        ioh->fd_write = fd_write;
+        ioh->opaque = opaque;
+        ioh->deleted = 0;
+    }
+    return 0;
+}
+
+int qemu_set_fd_handler(int fd,
+                        IOHandler *fd_read,
+                        IOHandler *fd_write,
+                        void *opaque)
+{
+    return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
+}
+
+void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds)
+{
+    IOHandlerRecord *ioh;
+
+    QLIST_FOREACH(ioh, &io_handlers, next) {
+        if (ioh->deleted)
+            continue;
+        if (ioh->fd_read &&
+            (!ioh->fd_read_poll ||
+             ioh->fd_read_poll(ioh->opaque) != 0)) {
+            FD_SET(ioh->fd, readfds);
+            if (ioh->fd > *pnfds)
+                *pnfds = ioh->fd;
+        }
+        if (ioh->fd_write) {
+            FD_SET(ioh->fd, writefds);
+            if (ioh->fd > *pnfds)
+                *pnfds = ioh->fd;
+        }
+    }
+}
+
+void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret)
+{
+    if (ret > 0) {
+        IOHandlerRecord *pioh, *ioh;
+
+        QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
+            if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) {
+                ioh->fd_read(ioh->opaque);
+            }
+            if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) {
+                ioh->fd_write(ioh->opaque);
+            }
+
+            /* Do this last in case read/write handlers marked it for deletion */
+            if (ioh->deleted) {
+                QLIST_REMOVE(ioh, next);
+                qemu_free(ioh);
+            }
+        }
+    }
+}
+
+/* reaping of zombies.  right now we're not passing the status to
+   anyone, but it would be possible to add a callback.  */
+#ifndef _WIN32
+typedef struct ChildProcessRecord {
+    int pid;
+    QLIST_ENTRY(ChildProcessRecord) next;
+} ChildProcessRecord;
+
+static QLIST_HEAD(, ChildProcessRecord) child_watches =
+    QLIST_HEAD_INITIALIZER(child_watches);
+
+static QEMUBH *sigchld_bh;
+
+static void sigchld_handler(int signal)
+{
+    qemu_bh_schedule(sigchld_bh);
+}
+
+static void sigchld_bh_handler(void *opaque)
+{
+    ChildProcessRecord *rec, *next;
+
+    QLIST_FOREACH_SAFE(rec, &child_watches, next, next) {
+        if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) {
+            QLIST_REMOVE(rec, next);
+            qemu_free(rec);
+        }
+    }
+}
+
+static void qemu_init_child_watch(void)
+{
+    struct sigaction act;
+    sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL);
+
+    act.sa_handler = sigchld_handler;
+    act.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGCHLD, &act, NULL);
+}
+
+int qemu_add_child_watch(pid_t pid)
+{
+    ChildProcessRecord *rec;
+
+    if (!sigchld_bh) {
+        qemu_init_child_watch();
+    }
+
+    QLIST_FOREACH(rec, &child_watches, next) {
+        if (rec->pid == pid) {
+            return 1;
+        }
+    }
+    rec = qemu_mallocz(sizeof(ChildProcessRecord));
+    rec->pid = pid;
+    QLIST_INSERT_HEAD(&child_watches, rec, next);
+    return 0;
+}
+#endif
index c736f42900e9484a33327cf79ac094ef99e86a66..65c9720d65be3eafcf7cfec6ec9141520c1a846b 100644 (file)
@@ -28,7 +28,7 @@
  */
 
 enum json_lexer_state {
-    ERROR = 0,
+    IN_ERROR = 0,
     IN_DQ_UCODE3,
     IN_DQ_UCODE2,
     IN_DQ_UCODE1,
@@ -150,7 +150,7 @@ static const uint8_t json_lexer[][256] =  {
     /* Zero */
     [IN_ZERO] = {
         TERMINAL(JSON_INTEGER),
-        ['0' ... '9'] = ERROR,
+        ['0' ... '9'] = IN_ERROR,
         ['.'] = IN_MANTISSA,
     },
 
@@ -302,7 +302,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
             lexer->token = qstring_new();
             new_state = IN_START;
             break;
-        case ERROR:
+        case IN_ERROR:
             return -EINVAL;
         default:
             break;
index 7ace9a2d7cd316e8b4615db65c37b84630fc5fd3..3b81b68b90a9c32d9cafa1d565921828cc2db619 100644 (file)
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -385,7 +385,20 @@ static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
             break;
         }
 
-        size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), HOST_LONG_BITS) / 8;
+        /* XXX bad kernel interface alert
+         * For dirty bitmap, kernel allocates array of size aligned to
+         * bits-per-long.  But for case when the kernel is 64bits and
+         * the userspace is 32bits, userspace can't align to the same
+         * bits-per-long, since sizeof(long) is different between kernel
+         * and user space.  This way, userspace will provide buffer which
+         * may be 4 bytes less than the kernel will use, resulting in
+         * userspace memory corruption (which is not detectable by valgrind
+         * too, in most cases).
+         * So for now, let's align to 64 instead of HOST_LONG_BITS here, in
+         * a hope that sizeof(long) wont become >8 any time soon.
+         */
+        size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
+                     /*HOST_LONG_BITS*/ 64) / 8;
         if (!d.dirty_bitmap) {
             d.dirty_bitmap = qemu_malloc(size);
         } else if (size > allocated_size) {
@@ -665,6 +678,15 @@ static CPUPhysMemoryClient kvm_cpu_phys_memory_client = {
     .log_stop = kvm_log_stop,
 };
 
+static void kvm_handle_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+
+    if (!qemu_cpu_is_self(env)) {
+        qemu_cpu_kick(env);
+    }
+}
+
 int kvm_init(void)
 {
     static const char upgrade_note[] =
@@ -773,6 +795,8 @@ int kvm_init(void)
 
     s->many_ioeventfds = kvm_check_many_ioeventfds();
 
+    cpu_interrupt_handler = kvm_handle_interrupt;
+
     return 0;
 
 err:
@@ -1181,7 +1205,7 @@ int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
         bp->use_count = 1;
         err = kvm_arch_insert_sw_breakpoint(current_env, bp);
         if (err) {
-            free(bp);
+            qemu_free(bp);
             return err;
         }
 
@@ -1305,7 +1329,7 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
     sigmask->len = 8;
     memcpy(sigmask->sigset, sigset, sizeof(*sigset));
     r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask);
-    free(sigmask);
+    qemu_free(sigmask);
 
     return r;
 }
index 30f6ec395658246ae257b3a10a768eb4f0a340bd..1c954521409d719f64991d1f2c77083b14fa9218 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "hw/hw.h"
 #include "exec-all.h"
 #include "gdbstub.h"
diff --git a/libcacard/Makefile b/libcacard/Makefile
new file mode 100644 (file)
index 0000000..4010029
--- /dev/null
@@ -0,0 +1,25 @@
+-include ../config-host.mak
+-include $(SRC_PATH)/Makefile.objs
+-include $(SRC_PATH)/rules.mak
+
+$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard)
+
+ifeq ($(CONFIG_WIN32),y)
+QEMU_THREAD=qemu-thread-win32.o
+else
+QEMU_THREAD=qemu-thread-posix.o
+endif
+
+
+QEMU_OBJS=$(addprefix ../, $(QEMU_THREAD) $(oslib-obj-y) $(trace-obj-y) qemu-malloc.o qemu-timer-common.o)
+
+QEMU_CFLAGS+=-I../
+
+vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o
+       $(call quiet-command,$(CC) $(libcacard_libs) -lrt -o $@ $^,"  LINK  $(TARGET_DIR)$@")
+
+all: vscclient
+
+clean:
+       rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient
+
diff --git a/libcacard/cac.c b/libcacard/cac.c
new file mode 100644 (file)
index 0000000..f34f63a
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * implement the applets for the CAC card.
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+
+#include "cac.h"
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816.h"
+
+#define CAC_GET_PROPERTIES  0x56
+#define CAC_GET_ACR         0x4c
+#define CAC_READ_BUFFER     0x52
+#define CAC_UPDATE_BUFFER   0x58
+#define CAC_SIGN_DECRYPT    0x42
+#define CAC_GET_CERTIFICATE 0x36
+
+/* private data for PKI applets */
+typedef struct CACPKIAppletDataStruct {
+    unsigned char *cert;
+    int cert_len;
+    unsigned char *cert_buffer;
+    int cert_buffer_len;
+    unsigned char *sign_buffer;
+    int sign_buffer_len;
+    VCardKey *key;
+} CACPKIAppletData;
+
+/*
+ * CAC applet private data
+ */
+struct VCardAppletPrivateStruct {
+    union {
+        CACPKIAppletData pki_data;
+        void *reserved;
+    } u;
+};
+
+/*
+ * handle all the APDU's that are common to all CAC applets
+ */
+static VCardStatus
+cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
+{
+    int ef;
+
+    switch (apdu->a_ins) {
+    case VCARD7816_INS_SELECT_FILE:
+        if (apdu->a_p1 != 0x02) {
+            /* let the 7816 code handle applet switches */
+            return VCARD_NEXT;
+        }
+        /* handle file id setting */
+        if (apdu->a_Lc != 2) {
+            *response = vcard_make_response(
+                VCARD7816_STATUS_ERROR_DATA_INVALID);
+            return VCARD_DONE;
+        }
+        /* CAC 1.0 only supports ef = 0 */
+        ef = apdu->a_body[0] | (apdu->a_body[1] << 8);
+        if (ef != 0) {
+            *response = vcard_make_response(
+                VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
+            return VCARD_DONE;
+        }
+        *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
+        return VCARD_DONE;
+    case VCARD7816_INS_GET_RESPONSE:
+    case VCARD7816_INS_VERIFY:
+        /* let the 7816 code handle these */
+        return VCARD_NEXT;
+    case CAC_GET_PROPERTIES:
+    case CAC_GET_ACR:
+        /* skip these for now, this will probably be needed */
+        *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+        return VCARD_DONE;
+    }
+    *response = vcard_make_response(
+        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+    return VCARD_DONE;
+}
+
+/*
+ *  reset the inter call state between applet selects
+ */
+static VCardStatus
+cac_applet_pki_reset(VCard *card, int channel)
+{
+    VCardAppletPrivate *applet_private = NULL;
+    CACPKIAppletData *pki_applet = NULL;
+    applet_private = vcard_get_current_applet_private(card, channel);
+    assert(applet_private);
+    pki_applet = &(applet_private->u.pki_data);
+
+    pki_applet->cert_buffer = NULL;
+    if (pki_applet->sign_buffer) {
+        qemu_free(pki_applet->sign_buffer);
+        pki_applet->sign_buffer = NULL;
+    }
+    pki_applet->cert_buffer_len = 0;
+    pki_applet->sign_buffer_len = 0;
+    return VCARD_DONE;
+}
+
+static VCardStatus
+cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
+                            VCardResponse **response)
+{
+    CACPKIAppletData *pki_applet = NULL;
+    VCardAppletPrivate *applet_private = NULL;
+    int size, next;
+    unsigned char *sign_buffer;
+    vcard_7816_status_t status;
+
+    applet_private = vcard_get_current_applet_private(card, apdu->a_channel);
+    assert(applet_private);
+    pki_applet = &(applet_private->u.pki_data);
+
+    switch (apdu->a_ins) {
+    case CAC_UPDATE_BUFFER:
+        *response = vcard_make_response(
+            VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
+        return VCARD_DONE;
+    case CAC_GET_CERTIFICATE:
+        if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) {
+            *response = vcard_make_response(
+                             VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+            break;
+        }
+        assert(pki_applet->cert != NULL);
+        size = apdu->a_Le;
+        if (pki_applet->cert_buffer == NULL) {
+            pki_applet->cert_buffer = pki_applet->cert;
+            pki_applet->cert_buffer_len = pki_applet->cert_len;
+        }
+        size = MIN(size, pki_applet->cert_buffer_len);
+        next = MIN(255, pki_applet->cert_buffer_len - size);
+        *response = vcard_response_new_bytes(
+                        card, pki_applet->cert_buffer, size,
+                        apdu->a_Le, next ?
+                        VCARD7816_SW1_WARNING_CHANGE :
+                        VCARD7816_SW1_SUCCESS,
+                        next);
+        pki_applet->cert_buffer += size;
+        pki_applet->cert_buffer_len -= size;
+        if ((*response == NULL) || (next == 0)) {
+            pki_applet->cert_buffer = NULL;
+        }
+        if (*response == NULL) {
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+        }
+        return VCARD_DONE;
+    case CAC_SIGN_DECRYPT:
+        if (apdu->a_p2 != 0) {
+            *response = vcard_make_response(
+                             VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+            break;
+        }
+        size = apdu->a_Lc;
+
+        sign_buffer = realloc(pki_applet->sign_buffer,
+                      pki_applet->sign_buffer_len+size);
+        if (sign_buffer == NULL) {
+            qemu_free(pki_applet->sign_buffer);
+            pki_applet->sign_buffer = NULL;
+            pki_applet->sign_buffer_len = 0;
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+            return VCARD_DONE;
+        }
+        memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size);
+        size += pki_applet->sign_buffer_len;
+        switch (apdu->a_p1) {
+        case  0x80:
+            /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for
+             * the rest */
+            pki_applet->sign_buffer = sign_buffer;
+            pki_applet->sign_buffer_len = size;
+            *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
+            return VCARD_DONE;
+        case 0x00:
+            /* we now have the whole buffer, do the operation, result will be
+             * in the sign_buffer */
+            status = vcard_emul_rsa_op(card, pki_applet->key,
+                                       sign_buffer, size);
+            if (status != VCARD7816_STATUS_SUCCESS) {
+                *response = vcard_make_response(status);
+                break;
+            }
+            *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le,
+                                                     VCARD7816_STATUS_SUCCESS);
+            if (*response == NULL) {
+                *response = vcard_make_response(
+                                VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+            }
+            break;
+        default:
+           *response = vcard_make_response(
+                                VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+            break;
+        }
+        qemu_free(sign_buffer);
+        pki_applet->sign_buffer = NULL;
+        pki_applet->sign_buffer_len = 0;
+        return VCARD_DONE;
+    case CAC_READ_BUFFER:
+        /* new CAC call, go ahead and use the old version for now */
+        /* TODO: implement */
+        *response = vcard_make_response(
+                                VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        return VCARD_DONE;
+    }
+    return cac_common_process_apdu(card, apdu, response);
+}
+
+
+static VCardStatus
+cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
+                           VCardResponse **response)
+{
+    switch (apdu->a_ins) {
+    case CAC_UPDATE_BUFFER:
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
+        return VCARD_DONE;
+    case CAC_READ_BUFFER:
+        /* new CAC call, go ahead and use the old version for now */
+        /* TODO: implement */
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        return VCARD_DONE;
+    }
+    return cac_common_process_apdu(card, apdu, response);
+}
+
+
+/*
+ * TODO: if we ever want to support general CAC middleware, we will need to
+ * implement the various containers.
+ */
+static VCardStatus
+cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu,
+                                  VCardResponse **response)
+{
+    switch (apdu->a_ins) {
+    case CAC_READ_BUFFER:
+    case CAC_UPDATE_BUFFER:
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        return VCARD_DONE;
+    default:
+        break;
+    }
+    return cac_common_process_apdu(card, apdu, response);
+}
+
+/*
+ * utilities for creating and destroying the private applet data
+ */
+static void
+cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
+{
+    CACPKIAppletData *pki_applet_data = NULL;
+    if (pki_applet_data == NULL) {
+        return;
+    }
+    pki_applet_data = &(applet_private->u.pki_data);
+    if (pki_applet_data->cert != NULL) {
+        qemu_free(pki_applet_data->cert);
+    }
+    if (pki_applet_data->sign_buffer != NULL) {
+        qemu_free(pki_applet_data->sign_buffer);
+    }
+    if (pki_applet_data->key != NULL) {
+        vcard_emul_delete_key(pki_applet_data->key);
+    }
+    qemu_free(applet_private);
+}
+
+static VCardAppletPrivate *
+cac_new_pki_applet_private(const unsigned char *cert,
+                           int cert_len, VCardKey *key)
+{
+    CACPKIAppletData *pki_applet_data = NULL;
+    VCardAppletPrivate *applet_private = NULL;
+    applet_private = (VCardAppletPrivate *)qemu_malloc(sizeof(VCardAppletPrivate));
+
+    pki_applet_data = &(applet_private->u.pki_data);
+    pki_applet_data->cert_buffer = NULL;
+    pki_applet_data->cert_buffer_len = 0;
+    pki_applet_data->sign_buffer = NULL;
+    pki_applet_data->sign_buffer_len = 0;
+    pki_applet_data->key = NULL;
+    pki_applet_data->cert = (unsigned char *)qemu_malloc(cert_len+1);
+    /*
+     * if we want to support compression, then we simply change the 0 to a 1
+     * and compress the cert data with libz
+     */
+    pki_applet_data->cert[0] = 0; /* not compressed */
+    memcpy(&pki_applet_data->cert[1], cert, cert_len);
+    pki_applet_data->cert_len = cert_len+1;
+
+    pki_applet_data->key = key;
+    return applet_private;
+}
+
+
+/*
+ * create a new cac applet which links to a given cert
+ */
+static VCardApplet *
+cac_new_pki_applet(int i, const unsigned char *cert,
+                   int cert_len, VCardKey *key)
+{
+    VCardAppletPrivate *applet_private = NULL;
+    VCardApplet *applet = NULL;
+    unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
+    int pki_aid_len = sizeof(pki_aid);
+
+    pki_aid[pki_aid_len-1] = i;
+
+    applet_private = cac_new_pki_applet_private(cert, cert_len, key);
+    if (applet_private == NULL) {
+        goto failure;
+    }
+    applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset,
+                              pki_aid, pki_aid_len);
+    if (applet == NULL) {
+        goto failure;
+    }
+    vcard_set_applet_private(applet, applet_private,
+                             cac_delete_pki_applet_private);
+    applet_private = NULL;
+
+    return applet;
+
+failure:
+    if (applet_private != NULL) {
+        cac_delete_pki_applet_private(applet_private);
+    }
+    return NULL;
+}
+
+
+static unsigned char cac_default_container_aid[] = {
+    0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 };
+static unsigned char cac_id_aid[] = {
+    0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 };
+/*
+ * Initialize the cac card. This is the only public function in this file. All
+ * the rest are connected through function pointers.
+ */
+VCardStatus
+cac_card_init(VReader *reader, VCard *card,
+              const char *params,
+              unsigned char * const *cert,
+              int cert_len[],
+              VCardKey *key[] /* adopt the keys*/,
+              int cert_count)
+{
+    int i;
+    VCardApplet *applet;
+
+    /* CAC Cards are VM Cards */
+    vcard_set_type(card, VCARD_VM);
+
+    /* create one PKI applet for each cert */
+    for (i = 0; i < cert_count; i++) {
+        applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]);
+        if (applet == NULL) {
+            goto failure;
+        }
+        vcard_add_applet(card, applet);
+    }
+
+    /* create a default blank container applet */
+    applet = vcard_new_applet(cac_applet_container_process_apdu,
+                              NULL, cac_default_container_aid,
+                              sizeof(cac_default_container_aid));
+    if (applet == NULL) {
+        goto failure;
+    }
+    vcard_add_applet(card, applet);
+
+    /* create a default blank container applet */
+    applet = vcard_new_applet(cac_applet_id_process_apdu,
+                              NULL, cac_id_aid,
+                              sizeof(cac_id_aid));
+    if (applet == NULL) {
+        goto failure;
+    }
+    vcard_add_applet(card, applet);
+    return VCARD_DONE;
+
+failure:
+    return VCARD_FAIL;
+}
+
diff --git a/libcacard/cac.h b/libcacard/cac.h
new file mode 100644 (file)
index 0000000..15a61be
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * defines the entry point for the cac card. Only used by cac.c anc
+ * vcard_emul_type.c
+ *
+ * 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.
+ */
+#ifndef CAC_H
+#define CAC_H 1
+#include "vcard.h"
+#include "vreader.h"
+/*
+ * Initialize the cac card. This is the only public function in this file. All
+ * the rest are connected through function pointers.
+ */
+VCardStatus cac_card_init(VReader *reader, VCard *card, const char *params,
+              unsigned char * const *cert, int cert_len[],
+              VCardKey *key[] /* adopt the keys*/,
+              int cert_count);
+
+/* not yet implemented */
+VCardStatus cac_is_cac_card(VReader *reader);
+#endif
diff --git a/libcacard/card_7816.c b/libcacard/card_7816.c
new file mode 100644 (file)
index 0000000..eeea849
--- /dev/null
@@ -0,0 +1,763 @@
+/*
+ * Implement the 7816 portion of the card spec
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816.h"
+
+/*
+ * set the status bytes based on the status word
+ */
+static void
+vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status)
+{
+    unsigned char sw1, sw2;
+    response->b_status = status; /* make sure the status and swX representations
+                                  * are consistent */
+    sw1 = (status >> 8) & 0xff;
+    sw2 = status & 0xff;
+    response->b_sw1 = sw1;
+    response->b_sw2 = sw2;
+    response->b_data[response->b_len] = sw1;
+    response->b_data[response->b_len+1] = sw2;
+}
+
+/*
+ * set the status bytes in a response buffer
+ */
+static void
+vcard_response_set_status_bytes(VCardResponse *response,
+                               unsigned char sw1, unsigned char sw2)
+{
+    response->b_status = sw1 << 8 | sw2;
+    response->b_sw1 = sw1;
+    response->b_sw2 = sw2;
+    response->b_data[response->b_len] = sw1;
+    response->b_data[response->b_len+1] = sw2;
+}
+
+/*
+ * allocate a VCardResponse structure, plus space for the data buffer, and
+ * set up everything but the resonse bytes.
+ */
+VCardResponse *
+vcard_response_new_data(unsigned char *buf, int len)
+{
+    VCardResponse *new_response;
+
+    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
+    new_response->b_data = qemu_malloc(len + 2);
+    memcpy(new_response->b_data, buf, len);
+    new_response->b_total_len = len+2;
+    new_response->b_len = len;
+    new_response->b_type = VCARD_MALLOC;
+    return new_response;
+}
+
+static VCardResponse *
+vcard_init_buffer_response(VCard *card, unsigned char *buf, int len)
+{
+    VCardResponse *response;
+    VCardBufferResponse *buffer_response;
+
+    buffer_response = vcard_get_buffer_response(card);
+    if (buffer_response) {
+        vcard_set_buffer_response(card, NULL);
+        vcard_buffer_response_delete(buffer_response);
+    }
+    buffer_response = vcard_buffer_response_new(buf, len);
+    if (buffer_response == NULL) {
+        return NULL;
+    }
+    response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES,
+                                               len > 255 ? 0 : len);
+    if (response == NULL) {
+        return NULL;
+    }
+    vcard_set_buffer_response(card, buffer_response);
+    return response;
+}
+
+/*
+ * general buffer to hold results from APDU calls
+ */
+VCardResponse *
+vcard_response_new(VCard *card, unsigned char *buf,
+                   int len, int Le, vcard_7816_status_t status)
+{
+    VCardResponse *new_response;
+
+    if (len > Le) {
+        return vcard_init_buffer_response(card, buf, len);
+    }
+    new_response = vcard_response_new_data(buf, len);
+    if (new_response == NULL) {
+        return NULL;
+    }
+    vcard_response_set_status(new_response, status);
+    return new_response;
+}
+
+/*
+ * general buffer to hold results from APDU calls
+ */
+VCardResponse *
+vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le,
+                         unsigned char sw1, unsigned char sw2)
+{
+    VCardResponse *new_response;
+
+    if (len > Le) {
+        return vcard_init_buffer_response(card, buf, len);
+    }
+    new_response = vcard_response_new_data(buf, len);
+    if (new_response == NULL) {
+        return NULL;
+    }
+    vcard_response_set_status_bytes(new_response, sw1, sw2);
+    return new_response;
+}
+
+/*
+ * get a new Reponse buffer that only has a status.
+ */
+static VCardResponse *
+vcard_response_new_status(vcard_7816_status_t status)
+{
+    VCardResponse *new_response;
+
+    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
+    new_response->b_data = &new_response->b_sw1;
+    new_response->b_len = 0;
+    new_response->b_total_len = 2;
+    new_response->b_type = VCARD_MALLOC_STRUCT;
+    vcard_response_set_status(new_response, status);
+    return new_response;
+}
+
+/*
+ * same as above, but specify the status as separate bytes
+ */
+VCardResponse *
+vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2)
+{
+    VCardResponse *new_response;
+
+    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
+    new_response->b_data = &new_response->b_sw1;
+    new_response->b_len = 0;
+    new_response->b_total_len = 2;
+    new_response->b_type = VCARD_MALLOC_STRUCT;
+    vcard_response_set_status_bytes(new_response, sw1, sw2);
+    return new_response;
+}
+
+
+/*
+ * free the response buffer. The Buffer has a type to handle the buffer
+ * allocated in other ways than through malloc.
+ */
+void
+vcard_response_delete(VCardResponse *response)
+{
+    if (response == NULL) {
+        return;
+    }
+    switch (response->b_type) {
+    case VCARD_MALLOC:
+        /* everything was malloc'ed */
+        if (response->b_data) {
+            qemu_free(response->b_data);
+        }
+        qemu_free(response);
+        break;
+    case VCARD_MALLOC_DATA:
+        /* only the data buffer was malloc'ed */
+        if (response->b_data) {
+            qemu_free(response->b_data);
+        }
+        break;
+    case VCARD_MALLOC_STRUCT:
+        /* only the structure was malloc'ed */
+        qemu_free(response);
+        break;
+    case VCARD_STATIC:
+        break;
+    }
+}
+
+/*
+ * decode the class bit and set our generic type field, channel, and
+ * secure messaging values.
+ */
+static vcard_7816_status_t
+vcard_apdu_set_class(VCardAPDU *apdu) {
+    apdu->a_channel = 0;
+    apdu->a_secure_messaging = 0;
+    apdu->a_type = apdu->a_cla & 0xf0;
+    apdu->a_gen_type = VCARD_7816_ISO;
+
+    /* parse the class  tables 8 & 9 of the 7816-4 Part 4 spec */
+    switch (apdu->a_type) {
+        /* we only support the basic types */
+    case 0x00:
+    case 0x80:
+    case 0x90:
+    case 0xa0:
+        apdu->a_channel = apdu->a_cla & 3;
+        apdu->a_secure_messaging = apdu->a_cla & 0xe;
+        break;
+    case 0xb0:
+    case 0xc0:
+        break;
+
+    case 0x10:
+    case 0x20:
+    case 0x30:
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+        /* Reserved for future use */
+        apdu->a_gen_type = VCARD_7816_RFU;
+        break;
+    case 0xd0:
+    case 0xe0:
+    case 0xf0:
+    default:
+        apdu->a_gen_type =
+            (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPIETARY;
+        break;
+    }
+    return VCARD7816_STATUS_SUCCESS;
+}
+
+/*
+ * set the Le and Lc fiels according to table 5 of the
+ * 7816-4 part 4 spec
+ */
+static vcard_7816_status_t
+vcard_apdu_set_length(VCardAPDU *apdu)
+{
+    int L, Le;
+
+    /* process according to table 5 of the 7816-4 Part 4 spec.
+     * variable names match the variables in the spec */
+    L = apdu->a_len-4; /* fixed APDU header */
+    apdu->a_Lc = 0;
+    apdu->a_Le = 0;
+    apdu->a_body = NULL;
+    switch (L) {
+    case 0:
+        /* 1 minimal apdu */
+        return VCARD7816_STATUS_SUCCESS;
+    case 1:
+        /* 2S only return values apdu */
+        /*   zero maps to 256 here */
+        apdu->a_Le = apdu->a_header->ah_Le ?
+                         apdu->a_header->ah_Le : 256;
+        return VCARD7816_STATUS_SUCCESS;
+    default:
+        /* if the ah_Le byte is zero and we have more than
+         * 1 byte in the header, then we must be using extended Le and Lc.
+         * process the extended now. */
+        if (apdu->a_header->ah_Le == 0) {
+            if (L < 3) {
+                /* coding error, need at least 3 bytes */
+                return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+            }
+            /* calculate the first extended value. Could be either Le or Lc */
+            Le = (apdu->a_header->ah_body[0] << 8)
+               || apdu->a_header->ah_body[1];
+            if (L == 3) {
+                /* 2E extended, return data only */
+                /*   zero maps to 65536 */
+                apdu->a_Le = Le ? Le : 65536;
+                return VCARD7816_STATUS_SUCCESS;
+            }
+            if (Le == 0) {
+                /* reserved for future use, probably for next time we need
+                 * to extend the lengths */
+                return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+            }
+            /* we know that the first extended value is Lc now */
+            apdu->a_Lc = Le;
+            apdu->a_body = &apdu->a_header->ah_body[2];
+            if (L == Le+3) {
+                /* 3E extended, only body parameters */
+                return VCARD7816_STATUS_SUCCESS;
+            }
+            if (L == Le+5) {
+                /* 4E extended, parameters and return data */
+                Le = (apdu->a_data[apdu->a_len-2] << 8)
+                   || apdu->a_data[apdu->a_len-1];
+                apdu->a_Le = Le ? Le : 65536;
+                return VCARD7816_STATUS_SUCCESS;
+            }
+            return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+        }
+        /* not extended */
+        apdu->a_Lc = apdu->a_header->ah_Le;
+        apdu->a_body = &apdu->a_header->ah_body[0];
+        if (L ==  apdu->a_Lc + 1) {
+            /* 3S only body parameters */
+            return VCARD7816_STATUS_SUCCESS;
+        }
+        if (L ==  apdu->a_Lc + 2) {
+            /* 4S parameters and return data */
+            Le = apdu->a_data[apdu->a_len-1];
+            apdu->a_Le = Le ?  Le : 256;
+            return VCARD7816_STATUS_SUCCESS;
+        }
+        break;
+    }
+    return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+}
+
+/*
+ * create a new APDU from a raw set of bytes. This will decode all the
+ * above fields. users of VCARDAPDU's can then depend on the already decoded
+ * values.
+ */
+VCardAPDU *
+vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status)
+{
+    VCardAPDU *new_apdu;
+
+    *status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
+    if (len < 4) {
+        *status = VCARD7816_STATUS_ERROR_WRONG_LENGTH;
+        return NULL;
+    }
+
+    new_apdu = (VCardAPDU *)qemu_malloc(sizeof(VCardAPDU));
+    new_apdu->a_data = qemu_malloc(len);
+    memcpy(new_apdu->a_data, raw_apdu, len);
+    new_apdu->a_len = len;
+    *status = vcard_apdu_set_class(new_apdu);
+    if (*status != VCARD7816_STATUS_SUCCESS) {
+        qemu_free(new_apdu);
+        return NULL;
+    }
+    *status = vcard_apdu_set_length(new_apdu);
+    if (*status != VCARD7816_STATUS_SUCCESS) {
+        qemu_free(new_apdu);
+        new_apdu = NULL;
+    }
+    return new_apdu;
+}
+
+void
+vcard_apdu_delete(VCardAPDU *apdu)
+{
+    if (apdu == NULL) {
+        return;
+    }
+    if (apdu->a_data) {
+        qemu_free(apdu->a_data);
+    }
+    qemu_free(apdu);
+}
+
+
+/*
+ * declare response buffers for all the 7816 defined error codes
+ */
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(
+                    VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS)
+VCARD_RESPONSE_NEW_STATIC_STATUS(
+                            VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID)
+VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL)
+
+/*
+ * return a single response code. This function cannot fail. It will always
+ * return a response.
+ */
+VCardResponse *
+vcard_make_response(vcard_7816_status_t status)
+{
+    VCardResponse *response = NULL;
+
+    switch (status) {
+    /* known 7816 response codes */
+    case VCARD7816_STATUS_SUCCESS:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_SUCCESS);
+    case VCARD7816_STATUS_WARNING:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING);
+    case VCARD7816_STATUS_WARNING_RET_CORUPT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_RET_CORUPT);
+    case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE);
+    case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED);
+    case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID);
+    case VCARD7816_STATUS_WARNING_CHANGE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_CHANGE);
+    case VCARD7816_STATUS_WARNING_FILE_FILLED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_WARNING_FILE_FILLED);
+    case VCARD7816_STATUS_EXC_ERROR:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_EXC_ERROR);
+    case VCARD7816_STATUS_EXC_ERROR_CHANGE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_EXC_ERROR_CHANGE);
+    case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+    case VCARD7816_STATUS_ERROR_WRONG_LENGTH:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_WRONG_LENGTH);
+    case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE);
+    case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED);
+    case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED);
+    case VCARD7816_STATUS_ERROR_DATA_INVALID:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_DATA_INVALID);
+    case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
+    case VCARD7816_STATUS_ERROR_DATA_NO_EF:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_DATA_NO_EF);
+    case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING);
+    case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT);
+    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS);
+    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA);
+    case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
+    case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
+    case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND);
+    case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE);
+    case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT);
+    case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+    case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT);
+    case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
+    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2);
+    case VCARD7816_STATUS_ERROR_INS_CODE_INVALID:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_INS_CODE_INVALID);
+    case VCARD7816_STATUS_ERROR_CLA_INVALID:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_CLA_INVALID);
+    case VCARD7816_STATUS_ERROR_GENERAL:
+        return VCARD_RESPONSE_GET_STATIC(
+                    VCARD7816_STATUS_ERROR_GENERAL);
+    default:
+        /* we don't know this status code, create a response buffer to
+         * hold it */
+        response = vcard_response_new_status(status);
+        if (response == NULL) {
+            /* couldn't allocate the buffer, return memmory error */
+            return VCARD_RESPONSE_GET_STATIC(
+                        VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+        }
+    }
+    assert(response);
+    return response;
+}
+
+/*
+ * Add File card support here if you need it.
+ */
+static VCardStatus
+vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu,
+                                   VCardResponse **response)
+{
+    /* TODO: if we want to support a virtual file system card, we do it here.
+     * It would probably be a pkcs #15 card type */
+    *response = vcard_make_response(
+                    VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+    return VCARD_DONE;
+}
+
+/*
+ * VM card (including java cards)
+ */
+static VCardStatus
+vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu,
+                          VCardResponse **response)
+{
+    int bytes_to_copy, next_byte_count, count;
+    VCardApplet *current_applet;
+    VCardBufferResponse *buffer_response;
+    vcard_7816_status_t status;
+
+    /* parse the class first */
+    if (apdu->a_gen_type !=  VCARD_7816_ISO) {
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        return VCARD_DONE;
+    }
+
+    /* use a switch so that if we need to support secure channel stuff later,
+     * we know where to put it */
+    switch (apdu->a_secure_messaging) {
+    case 0x0: /* no SM */
+        break;
+    case 0x4: /* proprietary SM */
+    case 0x8: /* header not authenticated */
+    case 0xc: /* header authenticated */
+    default:
+        /* for now, don't try to support secure channel stuff in the
+         * virtual card. */
+        *response = vcard_make_response(
+                        VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED);
+        return VCARD_DONE;
+    }
+
+    /* now parse the instruction */
+    switch (apdu->a_ins) {
+    case  VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */
+    case  VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */
+    case  VCARD7816_INS_GET_CHALLENGE: /* secure channel op */
+    case  VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */
+    case  VCARD7816_INS_ERASE_BINARY: /* applet control op */
+    case  VCARD7816_INS_READ_BINARY: /* applet control op */
+    case  VCARD7816_INS_WRITE_BINARY: /* applet control op */
+    case  VCARD7816_INS_UPDATE_BINARY: /* applet control op */
+    case  VCARD7816_INS_READ_RECORD: /* file op */
+    case  VCARD7816_INS_WRITE_RECORD: /* file op */
+    case  VCARD7816_INS_UPDATE_RECORD: /* file op */
+    case  VCARD7816_INS_APPEND_RECORD: /* file op */
+    case  VCARD7816_INS_ENVELOPE:
+    case  VCARD7816_INS_PUT_DATA:
+        *response = vcard_make_response(
+                            VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        break;
+
+    case  VCARD7816_INS_SELECT_FILE:
+        if (apdu->a_p1 != 0x04) {
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
+            break;
+        }
+
+        /* side effect, deselect the current applet if no applet has been found
+         * */
+        current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc);
+        vcard_select_applet(card, apdu->a_channel, current_applet);
+        if (current_applet) {
+            unsigned char *aid;
+            int aid_len;
+            aid = vcard_applet_get_aid(current_applet, &aid_len);
+            *response = vcard_response_new(card, aid, aid_len, apdu->a_Le,
+                                          VCARD7816_STATUS_SUCCESS);
+        } else {
+            *response = vcard_make_response(
+                             VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
+        }
+        break;
+
+    case  VCARD7816_INS_VERIFY:
+        if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) {
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_ERROR_WRONG_PARAMETERS);
+        } else {
+            if (apdu->a_Lc == 0) {
+                /* handle pin count if possible */
+                count = vcard_emul_get_login_count(card);
+                if (count < 0) {
+                    *response = vcard_make_response(
+                                    VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
+                } else {
+                    if (count > 0xf) {
+                        count = 0xf;
+                    }
+                    *response = vcard_response_new_status_bytes(
+                                                VCARD7816_SW1_WARNING_CHANGE,
+                                                                0xc0 | count);
+                    if (*response == NULL) {
+                        *response = vcard_make_response(
+                                    VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+                    }
+                }
+            } else {
+                    status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc);
+                *response = vcard_make_response(status);
+            }
+        }
+        break;
+
+    case VCARD7816_INS_GET_RESPONSE:
+        buffer_response = vcard_get_buffer_response(card);
+        if (!buffer_response) {
+            *response = vcard_make_response(
+                            VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
+            /* handle error */
+            break;
+        }
+        bytes_to_copy = MIN(buffer_response->len, apdu->a_Le);
+        next_byte_count = MIN(256, buffer_response->len - bytes_to_copy);
+        *response = vcard_response_new_bytes(
+                        card, buffer_response->current, bytes_to_copy,
+                        apdu->a_Le,
+                        next_byte_count ?
+                        VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS,
+                        next_byte_count);
+        buffer_response->current += bytes_to_copy;
+        buffer_response->len -= bytes_to_copy;
+        if (*response == NULL || (next_byte_count == 0)) {
+            vcard_set_buffer_response(card, NULL);
+            vcard_buffer_response_delete(buffer_response);
+        }
+        if (*response == NULL) {
+            *response =
+                vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
+        }
+        break;
+
+    case VCARD7816_INS_GET_DATA:
+        *response =
+            vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        break;
+
+    default:
+        *response =
+            vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+        break;
+    }
+
+    /* response should have been set somewhere */
+    assert(*response != NULL);
+    return VCARD_DONE;
+}
+
+
+/*
+ * APDU processing starts here. This routes the card processing stuff to the
+ * right location.
+ */
+VCardStatus
+vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
+{
+    VCardStatus status;
+    VCardBufferResponse *buffer_response;
+
+    /* first handle any PTS commands, which aren't really APDU's */
+    if (apdu->a_type == VCARD_7816_PTS) {
+        /* the PTS responses aren't really responses either */
+        *response = vcard_response_new_data(apdu->a_data, apdu->a_len);
+        /* PTS responses have no status bytes */
+        (*response)->b_total_len = (*response)->b_len;
+        return VCARD_DONE;
+    }
+    buffer_response = vcard_get_buffer_response(card);
+    if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) {
+        /* clear out buffer_response, return an error */
+        vcard_set_buffer_response(card, NULL);
+        vcard_buffer_response_delete(buffer_response);
+        *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR);
+        return VCARD_DONE;
+    }
+
+    status = vcard_process_applet_apdu(card, apdu, response);
+    if (status != VCARD_NEXT) {
+        return status;
+    }
+    switch (vcard_get_type(card)) {
+    case VCARD_FILE_SYSTEM:
+        return vcard7816_file_system_process_apdu(card, apdu, response);
+    case VCARD_VM:
+        return vcard7816_vm_process_apdu(card, apdu, response);
+    case VCARD_DIRECT:
+        /* if we are type direct, then the applet should handle everything */
+        assert("VCARD_DIRECT: applet failure");
+        break;
+    }
+    *response =
+        vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+    return VCARD_DONE;
+}
diff --git a/libcacard/card_7816.h b/libcacard/card_7816.h
new file mode 100644 (file)
index 0000000..2bb2a0d
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Implement the 7816 portion of the card spec
+ *
+ * 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.
+ */
+#ifndef CARD_7816_H
+#define CARD_7816_H  1
+
+#include "card_7816t.h"
+#include "vcardt.h"
+
+/*
+ * constructors for VCardResponse's
+ */
+/* response from a return buffer and a status */
+VCardResponse *vcard_response_new(VCard *card, unsigned char *buf, int len,
+                                  int Le, vcard_7816_status_t status);
+/* response from a return buffer and status bytes */
+VCardResponse *vcard_response_new_bytes(VCard *card, unsigned char *buf,
+                                        int len, int Le,
+                                        unsigned char sw1, unsigned char sw2);
+/* response from just status bytes */
+VCardResponse *vcard_response_new_status_bytes(unsigned char sw1,
+                                               unsigned char sw2);
+/* response from just status: NOTE this cannot fail, it will alwyas return a
+ * valid response, if it can't allocate memory, the response will be
+ * VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE */
+VCardResponse *vcard_make_response(vcard_7816_status_t status);
+
+/* create a raw response (status has already been encoded */
+VCardResponse *vcard_response_new_data(unsigned char *buf, int len);
+
+
+
+
+/*
+ * destructor for VCardResponse.
+ *  Can be called with a NULL response
+ */
+void vcard_response_delete(VCardResponse *response);
+
+/*
+ * constructor for VCardAPDU
+ */
+VCardAPDU *vcard_apdu_new(unsigned char *raw_apdu, int len,
+                          unsigned short *status);
+
+/*
+ * destructor for VCardAPDU
+ *  Can be called with a NULL apdu
+ */
+void vcard_apdu_delete(VCardAPDU *apdu);
+
+/*
+ * APDU processing starts here. This routes the card processing stuff to the
+ * right location. Always returns a valid response.
+ */
+VCardStatus vcard_process_apdu(VCard *card, VCardAPDU *apdu,
+                               VCardResponse **response);
+
+#endif
diff --git a/libcacard/card_7816t.h b/libcacard/card_7816t.h
new file mode 100644 (file)
index 0000000..9333285
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Implement the 7816 portion of the card spec
+ *
+ * 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.
+ */
+#ifndef CARD_7816T_H
+#define CARD_7816T_H 1
+
+typedef unsigned short vcard_7816_status_t;
+
+struct VCardResponseStruct {
+    unsigned char *b_data;
+    vcard_7816_status_t b_status;
+    unsigned char b_sw1;
+    unsigned char b_sw2;
+    int b_len;
+    int b_total_len;
+    enum VCardResponseBufferType {
+        VCARD_MALLOC,
+        VCARD_MALLOC_DATA,
+        VCARD_MALLOC_STRUCT,
+        VCARD_STATIC
+    } b_type;
+};
+
+#define VCARD_RESPONSE_NEW_STATIC_STATUS(stat) \
+static const VCardResponse VCardResponse##stat = \
+        {(unsigned char *)&VCardResponse##stat.b_sw1, (stat), ((stat) >> 8), \
+         ((stat) & 0xff), 0, 2, VCARD_STATIC};
+
+#define VCARD_RESPONSE_NEW_STATIC_STATUS_BYTES(sw1, sw2) \
+static const VCardResponse VCARDResponse##sw1 = \
+        {(unsigned char *)&VCardResponse##name.b_sw1, ((sw1) << 8 | (sw2)), \
+         (sw1), (sw2), 0, 2, VCARD_STATIC};
+
+/* cast away the const, callers need may need to 'free' the
+ * result, and const implies that they don't */
+#define VCARD_RESPONSE_GET_STATIC(name) \
+        ((VCardResponse *)(&VCardResponse##name))
+
+typedef enum {
+    VCARD_7816_ISO,
+    VCARD_7816_RFU,
+    VCARD_7816_PTS,
+    VCARD_7816_PROPIETARY
+} VCardAPDUType;
+
+
+/*
+ * 7816 header. All APDU's have this header.
+ * They must be laid out in this order.
+ */
+struct VCardAPDUHeader {
+    unsigned char ah_cla;
+    unsigned char ah_ins;
+    unsigned char ah_p1;
+    unsigned char ah_p2;
+    unsigned char ah_Le;
+    unsigned char ah_body[1]; /* indefinate length */
+};
+
+/*
+ * 7816 APDU structure. The raw bytes are stored in the union and can be
+ * accessed directly through u.data (which is aliased as a_data).
+ *
+ * Names of the fields match the 7816 documentation.
+ */
+struct VCardAPDUStruct {
+    int a_len;                /* length of the whole buffer, including header */
+    int a_Lc;                 /* 7816 Lc (parameter length) value */
+    int a_Le;                 /* 7816 Le (expected result length) value */
+    unsigned char *a_body;    /* pointer to the parameter */
+    int a_channel;            /* decoded channel */
+    int a_secure_messaging;   /* decoded secure messaging type */
+    int a_type;               /* decoded type from cla (top nibble of class) */
+    VCardAPDUType a_gen_type; /* generic type (7816, PROPRIETARY, RFU, etc) */
+    union {
+        struct VCardAPDUHeader *header;
+        unsigned char   *data;
+    } u;
+/* give the subfields a unified look */
+#define a_header u.header
+#define a_data u.data
+#define a_cla a_header->ah_cla /* class */
+#define a_ins a_header->ah_ins /* instruction */
+#define a_p1 a_header->ah_p1   /* parameter 1 */
+#define a_p2 a_header->ah_p2   /* parameter 2 */
+};
+
+/* 7816 status codes */
+#define VCARD7816_STATUS_SUCCESS                              0x9000
+#define VCARD7816_STATUS_WARNING                              0x6200
+#define VCARD7816_STATUS_WARNING_RET_CORUPT                   0x6281
+#define VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE            0x6282
+#define VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED        0x6283
+#define VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID           0x6284
+#define VCARD7816_STATUS_WARNING_CHANGE                       0x6300
+#define VCARD7816_STATUS_WARNING_FILE_FILLED                  0x6381
+#define VCARD7816_STATUS_EXC_ERROR                            0x6400
+#define VCARD7816_STATUS_EXC_ERROR_CHANGE                     0x6500
+#define VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE             0x6581
+#define VCARD7816_STATUS_ERROR_WRONG_LENGTH                   0x6700
+#define VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED              0x6800
+#define VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED          0x6881
+#define VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED           0x6882
+#define VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED          0x6900
+#define VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE 0x6981
+#define VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED         0x6982
+#define VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED         0x6983
+#define VCARD7816_STATUS_ERROR_DATA_INVALID                   0x6984
+#define VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED        0x6985
+#define VCARD7816_STATUS_ERROR_DATA_NO_EF                     0x6986
+#define VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING              0x6987
+#define VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT            0x6988
+#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS               0x6a00
+#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA       0x6a80
+#define VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED         0x6a81
+#define VCARD7816_STATUS_ERROR_FILE_NOT_FOUND                 0x6a82
+#define VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND               0x6a83
+#define VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE              0x6a84
+#define VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT            0x6a85
+#define VCARD7816_STATUS_ERROR_P1_P2_INCORRECT                0x6a86
+#define VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT          0x6a87
+#define VCARD7816_STATUS_ERROR_DATA_NOT_FOUND                 0x6a88
+#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2             0x6b00
+#define VCARD7816_STATUS_ERROR_INS_CODE_INVALID               0x6d00
+#define VCARD7816_STATUS_ERROR_CLA_INVALID                    0x6e00
+#define VCARD7816_STATUS_ERROR_GENERAL                        0x6f00
+/* 7816 sw1 codes */
+#define VCARD7816_SW1_SUCCESS               0x90
+#define VCARD7816_SW1_RESPONSE_BYTES        0x61
+#define VCARD7816_SW1_WARNING               0x62
+#define VCARD7816_SW1_WARNING_CHANGE        0x63
+#define VCARD7816_SW1_EXC_ERROR             0x64
+#define VCARD7816_SW1_EXC_ERROR_CHANGE      0x65
+#define VCARD7816_SW1_ERROR_WRONG_LENGTH    0x67
+#define VCARD7816_SW1_CLA_ERROR             0x68
+#define VCARD7816_SW1_COMMAND_ERROR         0x69
+#define VCARD7816_SW1_P1_P2_ERROR           0x6a
+#define VCARD7816_SW1_LE_ERROR              0x6c
+#define VCARD7816_SW1_INS_ERROR             0x6d
+#define VCARD7816_SW1_CLA_NOT_SUPPORTED     0x6e
+
+/* 7816 Instructions */
+#define VCARD7816_INS_MANAGE_CHANNEL        0x70
+#define VCARD7816_INS_EXTERNAL_AUTHENTICATE 0x82
+#define VCARD7816_INS_GET_CHALLENGE         0x84
+#define VCARD7816_INS_INTERNAL_AUTHENTICATE 0x88
+#define VCARD7816_INS_ERASE_BINARY          0x0e
+#define VCARD7816_INS_READ_BINARY           0xb0
+#define VCARD7816_INS_WRITE_BINARY          0xd0
+#define VCARD7816_INS_UPDATE_BINARY         0xd6
+#define VCARD7816_INS_READ_RECORD           0xb2
+#define VCARD7816_INS_WRITE_RECORD          0xd2
+#define VCARD7816_INS_UPDATE_RECORD         0xdc
+#define VCARD7816_INS_APPEND_RECORD         0xe2
+#define VCARD7816_INS_ENVELOPE              0xc2
+#define VCARD7816_INS_PUT_DATA              0xda
+#define VCARD7816_INS_GET_DATA              0xca
+#define VCARD7816_INS_SELECT_FILE           0xa4
+#define VCARD7816_INS_VERIFY                0x20
+#define VCARD7816_INS_GET_RESPONSE          0xc0
+
+#endif
diff --git a/libcacard/event.c b/libcacard/event.c
new file mode 100644 (file)
index 0000000..bb2f921
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * event queue implementation.
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "qemu-thread.h"
+
+#include "vcard.h"
+#include "vreader.h"
+#include "vevent.h"
+
+VEvent *
+vevent_new(VEventType type, VReader *reader, VCard *card)
+{
+    VEvent *new_vevent;
+
+    new_vevent = (VEvent *)qemu_malloc(sizeof(VEvent));
+    new_vevent->next = NULL;
+    new_vevent->type = type;
+    new_vevent->reader = vreader_reference(reader);
+    new_vevent->card = vcard_reference(card);
+
+    return new_vevent;
+}
+
+void
+vevent_delete(VEvent *vevent)
+{
+    if (vevent == NULL) {
+        return;
+    }
+    vreader_free(vevent->reader);
+    vcard_free(vevent->card);
+    qemu_free(vevent);
+}
+
+/*
+ * VEvent queue management
+ */
+
+static VEvent *vevent_queue_head;
+static VEvent *vevent_queue_tail;
+static QemuMutex vevent_queue_lock;
+static QemuCond vevent_queue_condition;
+
+void vevent_queue_init(void)
+{
+    qemu_mutex_init(&vevent_queue_lock);
+    qemu_cond_init(&vevent_queue_condition);
+    vevent_queue_head = vevent_queue_tail = NULL;
+}
+
+void
+vevent_queue_vevent(VEvent *vevent)
+{
+    vevent->next = NULL;
+    qemu_mutex_lock(&vevent_queue_lock);
+    if (vevent_queue_head) {
+        assert(vevent_queue_tail);
+        vevent_queue_tail->next = vevent;
+    } else {
+        vevent_queue_head = vevent;
+    }
+    vevent_queue_tail = vevent;
+    qemu_cond_signal(&vevent_queue_condition);
+    qemu_mutex_unlock(&vevent_queue_lock);
+}
+
+/* must have lock */
+static VEvent *
+vevent_dequeue_vevent(void)
+{
+    VEvent *vevent = NULL;
+    if (vevent_queue_head) {
+        vevent = vevent_queue_head;
+        vevent_queue_head = vevent->next;
+        vevent->next = NULL;
+    }
+    return vevent;
+}
+
+VEvent *vevent_wait_next_vevent(void)
+{
+    VEvent *vevent;
+
+    qemu_mutex_lock(&vevent_queue_lock);
+    while ((vevent = vevent_dequeue_vevent()) == NULL) {
+        qemu_cond_wait(&vevent_queue_condition, &vevent_queue_lock);
+    }
+    qemu_mutex_unlock(&vevent_queue_lock);
+    return vevent;
+}
+
+VEvent *vevent_get_next_vevent(void)
+{
+    VEvent *vevent;
+
+    qemu_mutex_lock(&vevent_queue_lock);
+    vevent = vevent_dequeue_vevent();
+    qemu_mutex_unlock(&vevent_queue_lock);
+    return vevent;
+}
+
diff --git a/libcacard/eventt.h b/libcacard/eventt.h
new file mode 100644 (file)
index 0000000..0dc7bd4
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef EVENTT_H
+#define EVENTT_H 1
+#include "vreadert.h"
+#include "vcardt.h"
+
+typedef struct VEventStruct VEvent;
+
+typedef enum {
+    VEVENT_READER_INSERT,
+    VEVENT_READER_REMOVE,
+    VEVENT_CARD_INSERT,
+    VEVENT_CARD_REMOVE,
+    VEVENT_LAST,
+} VEventType;
+
+struct VEventStruct {
+    VEvent *next;
+    VEventType type;
+    VReader *reader;
+    VCard *card;
+};
+#endif
+
+
diff --git a/libcacard/link_test.c b/libcacard/link_test.c
new file mode 100644 (file)
index 0000000..6f67a23
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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 <stdio.h>
+#include "vcard.h"
+
+VCardStatus cac_card_init(const char *flags, VCard *card,
+                const unsigned char *cert[],
+                int cert_len[], VCardKey *key[] /* adopt the keys*/,
+                int cert_count);
+/*
+ * this will crash... just test the linkage right now
+ */
+
+main(int argc, char **argv)
+{
+    VCard *card; /* no constructor yet */
+    cac_card_init("", card, NULL, 0, NULL, 0);
+}
+
diff --git a/libcacard/vcard.c b/libcacard/vcard.c
new file mode 100644 (file)
index 0000000..29b4cce
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * implement the Java card standard.
+ *
+ * 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 "qemu-common.h"
+
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816t.h"
+
+struct VCardAppletStruct {
+    VCardApplet   *next;
+    VCardProcessAPDU process_apdu;
+    VCardResetApplet reset_applet;
+    unsigned char *aid;
+    int aid_len;
+    void *applet_private;
+    VCardAppletPrivateFree applet_private_free;
+};
+
+struct VCardStruct {
+    int reference_count;
+    VCardApplet *applet_list;
+    VCardApplet *current_applet[MAX_CHANNEL];
+    VCardBufferResponse *vcard_buffer_response;
+    VCardType type;
+    VCardEmul *vcard_private;
+    VCardEmulFree vcard_private_free;
+    VCardGetAtr vcard_get_atr;
+};
+
+VCardBufferResponse *
+vcard_buffer_response_new(unsigned char *buffer, int size)
+{
+    VCardBufferResponse *new_buffer;
+
+    new_buffer = (VCardBufferResponse *)qemu_malloc(sizeof(VCardBufferResponse));
+    new_buffer->buffer = (unsigned char *)qemu_malloc(size);
+    memcpy(new_buffer->buffer, buffer, size);
+    new_buffer->buffer_len = size;
+    new_buffer->current = new_buffer->buffer;
+    new_buffer->len = size;
+    return new_buffer;
+}
+
+void
+vcard_buffer_response_delete(VCardBufferResponse *buffer_response)
+{
+    if (buffer_response == NULL) {
+        return;
+    }
+    if (buffer_response->buffer) {
+        qemu_free(buffer_response->buffer);
+    }
+    qemu_free(buffer_response);
+}
+
+
+/*
+ * clean up state after a reset
+ */
+void
+vcard_reset(VCard *card, VCardPower power)
+{
+    int i;
+    VCardApplet *applet = NULL;
+
+    if (card->type ==  VCARD_DIRECT) {
+        /* select the last applet */
+        VCardApplet *current_applet = NULL;
+        for (current_applet = card->applet_list; current_applet;
+                                       current_applet = current_applet->next) {
+            applet = current_applet;
+        }
+    }
+    for (i = 0; i < MAX_CHANNEL; i++) {
+        card->current_applet[i] = applet;
+    }
+    if (card->vcard_buffer_response) {
+        vcard_buffer_response_delete(card->vcard_buffer_response);
+        card->vcard_buffer_response = NULL;
+    }
+    vcard_emul_reset(card, power);
+    if (applet) {
+        applet->reset_applet(card, 0);
+    }
+}
+
+/* applet utilities */
+
+/*
+ * applet utilities
+ */
+/* constructor */
+VCardApplet *
+vcard_new_applet(VCardProcessAPDU applet_process_function,
+                 VCardResetApplet applet_reset_function,
+                 unsigned char *aid, int aid_len)
+{
+    VCardApplet *applet;
+
+    applet = (VCardApplet *)qemu_malloc(sizeof(VCardApplet));
+    applet->next = NULL;
+    applet->applet_private = NULL;
+    applet->applet_private_free = NULL;
+    applet->process_apdu = applet_process_function;
+    applet->reset_applet = applet_reset_function;
+
+    applet->aid = qemu_malloc(aid_len);
+    memcpy(applet->aid, aid, aid_len);
+    applet->aid_len = aid_len;
+    return applet;
+}
+
+/* destructor */
+void
+vcard_delete_applet(VCardApplet *applet)
+{
+    if (applet == NULL) {
+        return;
+    }
+    if (applet->applet_private_free) {
+        applet->applet_private_free(applet->applet_private);
+        applet->applet_private = NULL;
+    }
+    if (applet->aid) {
+        qemu_free(applet->aid);
+        applet->aid = NULL;
+    }
+    qemu_free(applet);
+}
+
+/* accessor */
+void
+vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private,
+                         VCardAppletPrivateFree private_free)
+{
+    if (applet->applet_private_free) {
+        applet->applet_private_free(applet->applet_private);
+    }
+    applet->applet_private = private;
+    applet->applet_private_free = private_free;
+}
+
+VCard *
+vcard_new(VCardEmul *private, VCardEmulFree private_free)
+{
+    VCard *new_card;
+    int i;
+
+    new_card = (VCard *)qemu_malloc(sizeof(VCard));
+    new_card->applet_list = NULL;
+    for (i = 0; i < MAX_CHANNEL; i++) {
+        new_card->current_applet[i] = NULL;
+    }
+    new_card->vcard_buffer_response = NULL;
+    new_card->type = VCARD_VM;
+    new_card->vcard_private = private;
+    new_card->vcard_private_free = private_free;
+    new_card->vcard_get_atr = NULL;
+    new_card->reference_count = 1;
+    return new_card;
+}
+
+VCard *
+vcard_reference(VCard *vcard)
+{
+    if (vcard == NULL) {
+        return NULL;
+    }
+    vcard->reference_count++;
+    return vcard;
+}
+
+void
+vcard_free(VCard *vcard)
+{
+    VCardApplet *current_applet = NULL;
+    VCardApplet *next_applet = NULL;
+
+    if (vcard == NULL) {
+        return;
+    }
+    vcard->reference_count--;
+    if (vcard->reference_count != 0) {
+        return;
+    }
+    if (vcard->vcard_private_free) {
+        (*vcard->vcard_private_free)(vcard->vcard_private);
+        vcard->vcard_private_free = 0;
+        vcard->vcard_private = 0;
+    }
+    for (current_applet = vcard->applet_list; current_applet;
+                                        current_applet = next_applet) {
+        next_applet = current_applet->next;
+        vcard_delete_applet(current_applet);
+    }
+    vcard_buffer_response_delete(vcard->vcard_buffer_response);
+    qemu_free(vcard);
+    return;
+}
+
+void
+vcard_get_atr(VCard *vcard, unsigned char *atr, int *atr_len)
+{
+    if (vcard->vcard_get_atr) {
+        (*vcard->vcard_get_atr)(vcard, atr, atr_len);
+        return;
+    }
+    vcard_emul_get_atr(vcard, atr, atr_len);
+}
+
+void
+vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr)
+{
+    card->vcard_get_atr = vcard_get_atr;
+}
+
+
+VCardStatus
+vcard_add_applet(VCard *card, VCardApplet *applet)
+{
+    applet->next = card->applet_list;
+    card->applet_list = applet;
+    /* if our card-type is direct, always call the applet */
+    if (card->type ==  VCARD_DIRECT) {
+        int i;
+
+        for (i = 0; i < MAX_CHANNEL; i++) {
+            card->current_applet[i] = applet;
+        }
+    }
+    return VCARD_DONE;
+}
+
+/*
+ * manage applets
+ */
+VCardApplet *
+vcard_find_applet(VCard *card, unsigned char *aid, int aid_len)
+{
+    VCardApplet *current_applet;
+
+    for (current_applet = card->applet_list; current_applet;
+                                        current_applet = current_applet->next) {
+        if (current_applet->aid_len != aid_len) {
+            continue;
+        }
+        if (memcmp(current_applet->aid, aid, aid_len) == 0) {
+            break;
+        }
+    }
+    return current_applet;
+}
+
+unsigned char *
+vcard_applet_get_aid(VCardApplet *applet, int *aid_len)
+{
+    if (applet == NULL) {
+        return NULL;
+    }
+    *aid_len = applet->aid_len;
+    return applet->aid;
+}
+
+
+void
+vcard_select_applet(VCard *card, int channel, VCardApplet *applet)
+{
+    assert(channel < MAX_CHANNEL);
+    card->current_applet[channel] = applet;
+    /* reset the applet */
+    if (applet && applet->reset_applet) {
+        applet->reset_applet(card, channel);
+    }
+}
+
+VCardAppletPrivate *
+vcard_get_current_applet_private(VCard *card, int channel)
+{
+    VCardApplet *applet = card->current_applet[channel];
+
+    if (applet == NULL) {
+        return NULL;
+    }
+    return applet->applet_private;
+}
+
+VCardStatus
+vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu,
+                          VCardResponse **response)
+{
+    if (card->current_applet[apdu->a_channel]) {
+        return card->current_applet[apdu->a_channel]->process_apdu(
+                                                        card, apdu, response);
+    }
+    return VCARD_NEXT;
+}
+
+/*
+ * Accessor functions
+ */
+/* accessor functions for the response buffer */
+VCardBufferResponse *
+vcard_get_buffer_response(VCard *card)
+{
+    return card->vcard_buffer_response;
+}
+
+void
+vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer)
+{
+    card->vcard_buffer_response = buffer;
+}
+
+
+/* accessor functions for the type */
+VCardType
+vcard_get_type(VCard *card)
+{
+    return card->type;
+}
+
+void
+vcard_set_type(VCard *card, VCardType type)
+{
+    card->type = type;
+}
+
+/* accessor for private data */
+VCardEmul *
+vcard_get_private(VCard *vcard)
+{
+    return vcard->vcard_private;
+}
+
diff --git a/libcacard/vcard.h b/libcacard/vcard.h
new file mode 100644 (file)
index 0000000..47dc703
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+#ifndef VCARD_H
+#define VCARD_H 1
+
+#include "vcardt.h"
+
+/*
+ * response buffer constructors and destructors.
+ *
+ * response buffers are used when we need to return more data than will fit in
+ * a normal APDU response (nominally 254 bytes).
+ */
+VCardBufferResponse *vcard_buffer_response_new(unsigned char *buffer, int size);
+void vcard_buffer_response_delete(VCardBufferResponse *buffer_response);
+
+
+/*
+ * clean up state on reset
+ */
+void vcard_reset(VCard *card, VCardPower power);
+
+/*
+ * applet utilities
+ */
+/*
+ * Constructor for a VCardApplet
+ */
+VCardApplet *vcard_new_applet(VCardProcessAPDU applet_process_function,
+                              VCardResetApplet applet_reset_function,
+                              unsigned char *aid, int aid_len);
+
+/*
+ * destructor for a VCardApplet
+ *  Can be called with a NULL applet
+ */
+void vcard_delete_applet(VCardApplet *applet);
+
+/* accessor - set the card type specific private data */
+void vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *_private,
+                              VCardAppletPrivateFree private_free);
+
+/* set type of vcard */
+void vcard_set_type(VCard *card, VCardType type);
+
+/*
+ * utilities interacting with the current applet
+ */
+/* add a new applet to a card */
+VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet);
+/* find the applet on the card with the given aid */
+VCardApplet *vcard_find_applet(VCard *card, unsigned char *aid, int aid_len);
+/* set the following applet to be current on the given channel */
+void vcard_select_applet(VCard *card, int channel, VCardApplet *applet);
+/* get the card type specific private data on the given channel */
+VCardAppletPrivate *vcard_get_current_applet_private(VCard *card, int channel);
+/* fetch the applet's id */
+unsigned char *vcard_applet_get_aid(VCardApplet *applet, int *aid_len);
+
+/* process the apdu for the current selected applet/file */
+VCardStatus vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu,
+                                      VCardResponse **response);
+/*
+ * VCard utilities
+ */
+/* constructor */
+VCard *vcard_new(VCardEmul *_private, VCardEmulFree private_free);
+/* get a reference */
+VCard *vcard_reference(VCard *);
+/* destructor (reference counted) */
+void vcard_free(VCard *);
+/* get the atr from the card */
+void vcard_get_atr(VCard *card, unsigned char *atr, int *atr_len);
+void vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr);
+
+/* accessor functions for the response buffer */
+VCardBufferResponse *vcard_get_buffer_response(VCard *card);
+void vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer);
+/* accessor functions for the type */
+VCardType vcard_get_type(VCard *card);
+/* get the private data */
+VCardEmul *vcard_get_private(VCard *card);
+
+#endif
diff --git a/libcacard/vcard_emul.h b/libcacard/vcard_emul.h
new file mode 100644 (file)
index 0000000..963563f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * This is the actual card emulator.
+ *
+ * These functions can be implemented in different ways on different platforms
+ * using the underlying system primitives. For Linux it uses NSS, though direct
+ * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
+ * used. On Windows CAPI could be used.
+ *
+ * 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.
+ */
+
+#ifndef VCARD_EMUL_H
+#define VCARD_EMUL_H 1
+
+#include "card_7816t.h"
+#include "vcard.h"
+#include "vcard_emul_type.h"
+
+/*
+ * types
+ */
+typedef enum {
+    VCARD_EMUL_OK = 0,
+    VCARD_EMUL_FAIL,
+    /* return values by vcard_emul_init */
+    VCARD_EMUL_INIT_ALREADY_INITED,
+} VCardEmulError;
+
+/* options are emul specific. call card_emul_parse_args to change a string
+ * To an options struct */
+typedef struct VCardEmulOptionsStruct VCardEmulOptions;
+
+/*
+ * Login functions
+ */
+/* return the number of login attempts still possible on the card. if unknown,
+ * return -1 */
+int vcard_emul_get_login_count(VCard *card);
+/* login into the card, return the 7816 status word (sw2 || sw1) */
+vcard_7816_status_t vcard_emul_login(VCard *card, unsigned char *pin,
+                                     int pin_len);
+
+/*
+ * key functions
+ */
+/* delete a key */
+void vcard_emul_delete_key(VCardKey *key);
+/* RSA sign/decrypt with the key, signature happens 'in place' */
+vcard_7816_status_t vcard_emul_rsa_op(VCard *card, VCardKey *key,
+                                  unsigned char *buffer, int buffer_size);
+
+void vcard_emul_reset(VCard *card, VCardPower power);
+void vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len);
+
+/* Re-insert of a card that has been removed by force removal */
+VCardEmulError vcard_emul_force_card_insert(VReader *vreader);
+/* Force a card removal even if the card is not physically removed */
+VCardEmulError vcard_emul_force_card_remove(VReader *vreader);
+
+VCardEmulOptions *vcard_emul_options(const char *args);
+VCardEmulError vcard_emul_init(const VCardEmulOptions *options);
+void vcard_emul_replay_insertion_events(void);
+void vcard_emul_usage(void);
+#endif
diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c
new file mode 100644 (file)
index 0000000..baada52
--- /dev/null
@@ -0,0 +1,1157 @@
+/*
+ * This is the actual card emulator.
+ *
+ * These functions can be implemented in different ways on different platforms
+ * using the underlying system primitives. For Linux it uses NSS, though direct
+ * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
+ * used. On Windows CAPI could be used.
+ *
+ * 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.
+ */
+
+/*
+ * NSS headers
+ */
+
+/* avoid including prototypes.h that redefines uint32 */
+#define NO_NSPR_10_SUPPORT
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <cert.h>
+#include <key.h>
+#include <secmod.h>
+#include <prthread.h>
+#include <secerr.h>
+
+#include "qemu-common.h"
+
+#include "vcard.h"
+#include "card_7816t.h"
+#include "vcard_emul.h"
+#include "vreader.h"
+#include "vevent.h"
+
+struct VCardKeyStruct {
+    CERTCertificate *cert;
+    PK11SlotInfo *slot;
+    SECKEYPrivateKey *key;
+};
+
+
+typedef struct VirtualReaderOptionsStruct VirtualReaderOptions;
+
+struct VReaderEmulStruct {
+    PK11SlotInfo *slot;
+    VCardEmulType default_type;
+    char *type_params;
+    PRBool present;
+    int     series;
+    VCard *saved_vcard;
+};
+
+/*
+ *  NSS Specific options
+ */
+struct VirtualReaderOptionsStruct {
+    char *name;
+    char *vname;
+    VCardEmulType card_type;
+    char *type_params;
+    char **cert_name;
+    int cert_count;
+};
+
+struct VCardEmulOptionsStruct {
+    void *nss_db;
+    VirtualReaderOptions *vreader;
+    int vreader_count;
+    VCardEmulType hw_card_type;
+    const char *hw_type_params;
+    PRBool use_hw;
+};
+
+static int nss_emul_init;
+
+/* if we have more that just the slot, define
+ * VCardEmulStruct here */
+
+/*
+ * allocate the set of arrays for certs, cert_len, key
+ */
+static PRBool
+vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp,
+                        VCardKey ***keysp, int cert_count)
+{
+    *certsp = NULL;
+    *cert_lenp = NULL;
+    *keysp = NULL;
+    *certsp = (unsigned char **)qemu_malloc(sizeof(unsigned char *)*cert_count);
+    *cert_lenp = (int *)qemu_malloc(sizeof(int)*cert_count);
+    *keysp = (VCardKey **)qemu_malloc(sizeof(VCardKey *)*cert_count);
+    return PR_TRUE;
+}
+
+/*
+ * Emulator specific card information
+ */
+typedef struct CardEmulCardStruct CardEmulPrivate;
+
+static VCardEmul *
+vcard_emul_new_card(PK11SlotInfo *slot)
+{
+    PK11_ReferenceSlot(slot);
+    /* currently we don't need anything other than the slot */
+    return (VCardEmul *)slot;
+}
+
+static void
+vcard_emul_delete_card(VCardEmul *vcard_emul)
+{
+    PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul;
+    if (slot == NULL) {
+        return;
+    }
+    PK11_FreeSlot(slot);
+}
+
+static PK11SlotInfo *
+vcard_emul_card_get_slot(VCard *card)
+{
+    /* note, the card is holding the reference, no need to get another one */
+    return (PK11SlotInfo *)vcard_get_private(card);
+}
+
+
+/*
+ * key functions
+ */
+/* private constructure */
+static VCardKey *
+vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert)
+{
+    VCardKey *key;
+
+    key = (VCardKey *)qemu_malloc(sizeof(VCardKey));
+    key->slot = PK11_ReferenceSlot(slot);
+    key->cert = CERT_DupCertificate(cert);
+    /* NOTE: if we aren't logged into the token, this could return NULL */
+    /* NOTE: the cert is a temp cert, not necessarily the cert in the token,
+     * use the DER version of this function */
+    key->key = PK11_FindKeyByDERCert(slot, cert, NULL);
+    return key;
+}
+
+/* destructor */
+void
+vcard_emul_delete_key(VCardKey *key)
+{
+    if (!nss_emul_init || (key == NULL)) {
+        return;
+    }
+    if (key->key) {
+        SECKEY_DestroyPrivateKey(key->key);
+        key->key = NULL;
+    }
+    if (key->cert) {
+        CERT_DestroyCertificate(key->cert);
+    }
+    if (key->slot) {
+        PK11_FreeSlot(key->slot);
+    }
+    return;
+}
+
+/*
+ * grab the nss key from a VCardKey. If it doesn't exist, try to look it up
+ */
+static SECKEYPrivateKey *
+vcard_emul_get_nss_key(VCardKey *key)
+{
+    if (key->key) {
+        return key->key;
+    }
+    /* NOTE: if we aren't logged into the token, this could return NULL */
+    key->key = PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL);
+    return key->key;
+}
+
+/*
+ * Map NSS errors to 7816 errors
+ */
+static vcard_7816_status_t
+vcard_emul_map_error(int error)
+{
+    switch (error) {
+    case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
+        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+    case SEC_ERROR_BAD_DATA:
+    case SEC_ERROR_OUTPUT_LEN:
+    case SEC_ERROR_INPUT_LEN:
+    case SEC_ERROR_INVALID_ARGS:
+    case SEC_ERROR_INVALID_ALGORITHM:
+    case SEC_ERROR_NO_KEY:
+    case SEC_ERROR_INVALID_KEY:
+    case SEC_ERROR_DECRYPTION_DISALLOWED:
+        return VCARD7816_STATUS_ERROR_DATA_INVALID;
+    case SEC_ERROR_NO_MEMORY:
+        return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
+    }
+    return VCARD7816_STATUS_EXC_ERROR_CHANGE;
+}
+
+/* RSA sign/decrypt with the key, signature happens 'in place' */
+vcard_7816_status_t
+vcard_emul_rsa_op(VCard *card, VCardKey *key,
+                  unsigned char *buffer, int buffer_size)
+{
+    SECKEYPrivateKey *priv_key;
+    unsigned signature_len;
+    SECStatus rv;
+
+    if ((!nss_emul_init) || (key == NULL)) {
+        /* couldn't get the key, indicate that we aren't logged in */
+        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+    }
+    priv_key = vcard_emul_get_nss_key(key);
+
+    /*
+     * this is only true of the rsa signature
+     */
+    signature_len = PK11_SignatureLen(priv_key);
+    if (buffer_size != signature_len) {
+        return  VCARD7816_STATUS_ERROR_DATA_INVALID;
+    }
+    rv = PK11_PrivDecryptRaw(priv_key, buffer, &signature_len, signature_len,
+                             buffer, buffer_size);
+    if (rv != SECSuccess) {
+        return vcard_emul_map_error(PORT_GetError());
+    }
+    assert(buffer_size == signature_len);
+    return VCARD7816_STATUS_SUCCESS;
+}
+
+/*
+ * Login functions
+ */
+/* return the number of login attempts still possible on the card. if unknown,
+ * return -1 */
+int
+vcard_emul_get_login_count(VCard *card)
+{
+    return -1;
+}
+
+/* login into the card, return the 7816 status word (sw2 || sw1) */
+vcard_7816_status_t
+vcard_emul_login(VCard *card, unsigned char *pin, int pin_len)
+{
+    PK11SlotInfo *slot;
+    unsigned char *pin_string = NULL;
+    int i;
+    SECStatus rv;
+
+    if (!nss_emul_init) {
+        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+    }
+    slot = vcard_emul_card_get_slot(card);
+     /* We depend on the PKCS #11 module internal login state here because we
+      * create a separate process to handle each guest instance. If we needed
+      * to handle multiple guests from one process, then we would need to keep
+      * a lot of extra state in our card structure
+      * */
+    pin_string = qemu_malloc(pin_len+1);
+    memcpy(pin_string, pin, pin_len);
+    pin_string[pin_len] = 0;
+
+    /* handle CAC expanded pins correctly */
+    for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) {
+        pin_string[i] = 0;
+    }
+
+    rv = PK11_Authenticate(slot, PR_FALSE, pin_string);
+    memset(pin_string, 0, pin_len);  /* don't let the pin hang around in memory
+                                        to be snooped */
+    qemu_free(pin_string);
+    if (rv == SECSuccess) {
+        return VCARD7816_STATUS_SUCCESS;
+    }
+    /* map the error from port get error */
+    return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
+}
+
+void
+vcard_emul_reset(VCard *card, VCardPower power)
+{
+    PK11SlotInfo *slot;
+
+    if (!nss_emul_init) {
+        return;
+    }
+
+    /*
+     * if we reset the card (either power on or power off), we lose our login
+     * state
+     */
+    /* TODO: we may also need to send insertion/removal events? */
+    slot = vcard_emul_card_get_slot(card);
+    PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */
+    return;
+}
+
+
+static VReader *
+vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot)
+{
+    VReaderList *reader_list = vreader_get_reader_list();
+    VReaderListEntry *current_entry = NULL;
+
+    if (reader_list == NULL) {
+        return NULL;
+    }
+    for (current_entry = vreader_list_get_first(reader_list); current_entry;
+                        current_entry = vreader_list_get_next(current_entry)) {
+        VReader *reader = vreader_list_get_reader(current_entry);
+        VReaderEmul *reader_emul = vreader_get_private(reader);
+        if (reader_emul->slot == slot) {
+            return reader;
+        }
+        vreader_free(reader);
+    }
+
+    return NULL;
+}
+
+/*
+ * create a new reader emul
+ */
+static VReaderEmul *
+vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params)
+{
+    VReaderEmul *new_reader_emul;
+
+    new_reader_emul = (VReaderEmul *)qemu_malloc(sizeof(VReaderEmul));
+
+    new_reader_emul->slot = PK11_ReferenceSlot(slot);
+    new_reader_emul->default_type = type;
+    new_reader_emul->type_params = strdup(params);
+    new_reader_emul->present = PR_FALSE;
+    new_reader_emul->series = 0;
+    new_reader_emul->saved_vcard = NULL;
+    return new_reader_emul;
+}
+
+static void
+vreader_emul_delete(VReaderEmul *vreader_emul)
+{
+    if (vreader_emul == NULL) {
+        return;
+    }
+    if (vreader_emul->slot) {
+        PK11_FreeSlot(vreader_emul->slot);
+    }
+    if (vreader_emul->type_params) {
+        qemu_free(vreader_emul->type_params);
+    }
+    qemu_free(vreader_emul);
+}
+
+/*
+ *  TODO: move this to emulater non-specific file
+ */
+static VCardEmulType
+vcard_emul_get_type(VReader *vreader)
+{
+    VReaderEmul *vreader_emul;
+
+    vreader_emul = vreader_get_private(vreader);
+    if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) {
+        return vreader_emul->default_type;
+    }
+
+    return vcard_emul_type_select(vreader);
+}
+/*
+ *  TODO: move this to emulater non-specific file
+ */
+static const char *
+vcard_emul_get_type_params(VReader *vreader)
+{
+    VReaderEmul *vreader_emul;
+
+    vreader_emul = vreader_get_private(vreader);
+    if (vreader_emul && vreader_emul->type_params) {
+        return vreader_emul->type_params;
+    }
+
+    return "";
+}
+
+/* pull the slot out of the reader private data */
+static PK11SlotInfo *
+vcard_emul_reader_get_slot(VReader *vreader)
+{
+    VReaderEmul *vreader_emul = vreader_get_private(vreader);
+    if (vreader_emul == NULL) {
+        return NULL;
+    }
+    return vreader_emul->slot;
+}
+
+/*
+ *  Card ATR's map to physical cards. VCARD_ATR_PREFIX will set appropriate
+ *  historical bytes for any software emulated card. The remaining bytes can be
+ *  used to indicate the actual emulator
+ */
+static const unsigned char nss_atr[] = { VCARD_ATR_PREFIX(3), 'N', 'S', 'S' };
+
+void
+vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len)
+{
+    int len = MIN(sizeof(nss_atr), *atr_len);
+    assert(atr != NULL);
+
+    memcpy(atr, nss_atr, len);
+    *atr_len = len;
+    return;
+}
+
+/*
+ * create a new card from certs and keys
+ */
+static VCard *
+vcard_emul_make_card(VReader *reader,
+                     unsigned char * const *certs, int *cert_len,
+                     VCardKey *keys[], int cert_count)
+{
+    VCardEmul *vcard_emul;
+    VCard *vcard;
+    PK11SlotInfo *slot;
+    VCardEmulType type;
+    const char *params;
+
+    type = vcard_emul_get_type(reader);
+
+    /* ignore the inserted card */
+    if (type == VCARD_EMUL_NONE) {
+        return NULL;
+    }
+    slot = vcard_emul_reader_get_slot(reader);
+    if (slot == NULL) {
+        return NULL;
+    }
+
+    params = vcard_emul_get_type_params(reader);
+    /* params these can be NULL */
+
+    vcard_emul = vcard_emul_new_card(slot);
+    if (vcard_emul == NULL) {
+        return NULL;
+    }
+    vcard = vcard_new(vcard_emul, vcard_emul_delete_card);
+    if (vcard == NULL) {
+        vcard_emul_delete_card(vcard_emul);
+        return NULL;
+    }
+    vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count);
+    return vcard;
+}
+
+
+/*
+ * 'clone' a physical card as a virtual card
+ */
+static VCard *
+vcard_emul_mirror_card(VReader *vreader)
+{
+    /*
+     * lookup certs using the C_FindObjects. The Stan Cert handle won't give
+     * us the real certs until we log in.
+     */
+    PK11GenericObject *firstObj, *thisObj;
+    int cert_count;
+    unsigned char **certs;
+    int *cert_len;
+    VCardKey **keys;
+    PK11SlotInfo *slot;
+    PRBool ret;
+
+    slot = vcard_emul_reader_get_slot(vreader);
+    if (slot == NULL) {
+        return NULL;
+    }
+
+    firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE);
+    if (firstObj == NULL) {
+        return NULL;
+    }
+
+    /* count the certs */
+    cert_count = 0;
+    for (thisObj = firstObj; thisObj;
+                             thisObj = PK11_GetNextGenericObject(thisObj)) {
+        cert_count++;
+    }
+
+    if (cert_count == 0) {
+        PK11_DestroyGenericObjects(firstObj);
+        return NULL;
+    }
+
+    /* allocate the arrays */
+    ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
+    if (ret == PR_FALSE) {
+        return NULL;
+    }
+
+    /* fill in the arrays */
+    cert_count = 0;
+    for (thisObj = firstObj; thisObj;
+                             thisObj = PK11_GetNextGenericObject(thisObj)) {
+        SECItem derCert;
+        CERTCertificate *cert;
+        SECStatus rv;
+
+        rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj,
+                                   CKA_VALUE, &derCert);
+        if (rv != SECSuccess) {
+            continue;
+        }
+        /* create floating temp cert. This gives us a cert structure even if
+         * the token isn't logged in */
+        cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
+                                       NULL, PR_FALSE, PR_TRUE);
+        SECITEM_FreeItem(&derCert, PR_FALSE);
+        if (cert == NULL) {
+            continue;
+        }
+
+        certs[cert_count] = cert->derCert.data;
+        cert_len[cert_count] = cert->derCert.len;
+        keys[cert_count] = vcard_emul_make_key(slot, cert);
+        cert_count++;
+        CERT_DestroyCertificate(cert); /* key obj still has a reference */
+    }
+
+    /* now create the card */
+    return vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);
+}
+
+static VCardEmulType default_card_type = VCARD_EMUL_NONE;
+static const char *default_type_params = "";
+
+/*
+ * This thread looks for card and reader insertions and puts events on the
+ * event queue
+ */
+static void
+vcard_emul_event_thread(void *arg)
+{
+    PK11SlotInfo *slot;
+    VReader *vreader;
+    VReaderEmul *vreader_emul;
+    VCard *vcard;
+    SECMODModule *module = (SECMODModule *)arg;
+
+    do {
+        slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
+        if (slot == NULL) {
+            break;
+        }
+        vreader = vcard_emul_find_vreader_from_slot(slot);
+        if (vreader == NULL) {
+            /* new vreader */
+            vreader_emul = vreader_emul_new(slot, default_card_type,
+                                            default_type_params);
+            vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
+                                  vreader_emul_delete);
+            PK11_FreeSlot(slot);
+            slot = NULL;
+            vreader_add_reader(vreader);
+            vreader_free(vreader);
+            continue;
+        }
+        /* card remove/insert */
+        vreader_emul = vreader_get_private(vreader);
+        if (PK11_IsPresent(slot)) {
+            int series = PK11_GetSlotSeries(slot);
+            if (series != vreader_emul->series) {
+                if (vreader_emul->present) {
+                    vreader_insert_card(vreader, NULL);
+                }
+                vcard = vcard_emul_mirror_card(vreader);
+                vreader_insert_card(vreader, vcard);
+                vcard_free(vcard);
+            }
+            vreader_emul->series = series;
+            vreader_emul->present = 1;
+            vreader_free(vreader);
+            PK11_FreeSlot(slot);
+            continue;
+        }
+        if (vreader_emul->present) {
+            vreader_insert_card(vreader, NULL);
+        }
+        vreader_emul->series = 0;
+        vreader_emul->present = 0;
+        PK11_FreeSlot(slot);
+        vreader_free(vreader);
+    } while (1);
+}
+
+/* if the card is inserted when we start up, make sure our state is correct */
+static void
+vcard_emul_init_series(VReader *vreader, VCard *vcard)
+{
+    VReaderEmul *vreader_emul = vreader_get_private(vreader);
+    PK11SlotInfo *slot = vreader_emul->slot;
+
+    vreader_emul->present = PK11_IsPresent(slot);
+    vreader_emul->series = PK11_GetSlotSeries(slot);
+    if (vreader_emul->present == 0) {
+        vreader_insert_card(vreader, NULL);
+    }
+}
+
+/*
+ * each module has a separate wait call, create a thread for each module that
+ * we are using.
+ */
+static void
+vcard_emul_new_event_thread(SECMODModule *module)
+{
+    PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread,
+                     module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD,
+                     PR_UNJOINABLE_THREAD, 0);
+}
+
+static const VCardEmulOptions default_options = {
+    .nss_db = NULL,
+    .vreader = NULL,
+    .vreader_count = 0,
+    .hw_card_type = VCARD_EMUL_CAC,
+    .hw_type_params = "",
+    .use_hw = PR_TRUE
+};
+
+
+/*
+ *  NSS needs the app to supply a password prompt. In our case the only time
+ *  the password is supplied is as part of the Login APDU. The actual password
+ *  is passed in the pw_arg in that case. In all other cases pw_arg should be
+ *  NULL.
+ */
+static char *
+vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg)
+{
+    /* if it didn't work the first time, don't keep trying */
+    if (retries) {
+        return NULL;
+    }
+    /* we are looking up a password when we don't have one in hand */
+    if (pw_arg == NULL) {
+        return NULL;
+    }
+    /* TODO: we really should verify that were are using the right slot */
+    return PORT_Strdup(pw_arg);
+}
+
+/* Force a card removal even if the card is not physically removed */
+VCardEmulError
+vcard_emul_force_card_remove(VReader *vreader)
+{
+    if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
+        return VCARD_EMUL_FAIL; /* card is already removed */
+    }
+
+    /* OK, remove it */
+    vreader_insert_card(vreader, NULL);
+    return VCARD_EMUL_OK;
+}
+
+/* Re-insert of a card that has been removed by force removal */
+VCardEmulError
+vcard_emul_force_card_insert(VReader *vreader)
+{
+    VReaderEmul *vreader_emul;
+    VCard *vcard;
+
+    if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
+        return VCARD_EMUL_FAIL; /* card is already removed */
+    }
+    vreader_emul = vreader_get_private(vreader);
+
+    /* if it's a softcard, get the saved vcard from the reader emul structure */
+    if (vreader_emul->saved_vcard) {
+        vcard = vcard_reference(vreader_emul->saved_vcard);
+    } else {
+        /* it must be a physical card, rebuild it */
+        if (!PK11_IsPresent(vreader_emul->slot)) {
+            /* physical card has been removed, not way to reinsert it */
+            return VCARD_EMUL_FAIL;
+        }
+        vcard = vcard_emul_mirror_card(vreader);
+    }
+    vreader_insert_card(vreader, vcard);
+    vcard_free(vcard);
+
+    return VCARD_EMUL_OK;
+}
+
+
+static PRBool
+module_has_removable_hw_slots(SECMODModule *mod)
+{
+    int i;
+    PRBool ret = PR_FALSE;
+    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
+
+    if (!moduleLock) {
+        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+        return ret;
+    }
+    SECMOD_GetReadLock(moduleLock);
+    for (i = 0; i < mod->slotCount; i++) {
+        PK11SlotInfo *slot = mod->slots[i];
+        if (PK11_IsRemovable(slot) && PK11_IsHW(slot)) {
+            ret = PR_TRUE;
+            break;
+        }
+    }
+    SECMOD_ReleaseReadLock(moduleLock);
+    return ret;
+}
+
+/* Previously we returned FAIL if no readers found. This makes
+ * no sense when using hardware, since there may be no readers connected
+ * at the time vcard_emul_init is called, but they will be properly
+ * recognized later. So Instead return FAIL only if no_hw==1 and no
+ * vcards can be created (indicates error with certificates provided
+ * or db), or if any other higher level error (NSS error, missing coolkey). */
+static int vcard_emul_init_called;
+
+VCardEmulError
+vcard_emul_init(const VCardEmulOptions *options)
+{
+    SECStatus rv;
+    PRBool ret, has_readers = PR_FALSE, need_coolkey_module;
+    VReader *vreader;
+    VReaderEmul *vreader_emul;
+    SECMODListLock *module_lock;
+    SECMODModuleList *module_list;
+    SECMODModuleList *mlp;
+    int i;
+
+    if (vcard_emul_init_called) {
+        return VCARD_EMUL_INIT_ALREADY_INITED;
+    }
+    vcard_emul_init_called = 1;
+    vreader_init();
+    vevent_queue_init();
+
+    if (options == NULL) {
+        options = &default_options;
+    }
+
+    /* first initialize NSS */
+    if (options->nss_db) {
+        rv = NSS_Init(options->nss_db);
+    } else {
+        rv = NSS_Init("sql:/etc/pki/nssdb");
+    }
+    if (rv != SECSuccess) {
+        return VCARD_EMUL_FAIL;
+    }
+    /* Set password callback function */
+    PK11_SetPasswordFunc(vcard_emul_get_password);
+
+    /* set up soft cards emulated by software certs rather than physical cards
+     * */
+    for (i = 0; i < options->vreader_count; i++) {
+        int j;
+        int cert_count;
+        unsigned char **certs;
+        int *cert_len;
+        VCardKey **keys;
+        PK11SlotInfo *slot;
+
+        slot = PK11_FindSlotByName(options->vreader[i].name);
+        if (slot == NULL) {
+            continue;
+        }
+        vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type,
+                                        options->vreader[i].type_params);
+        vreader = vreader_new(options->vreader[i].vname, vreader_emul,
+                              vreader_emul_delete);
+        vreader_add_reader(vreader);
+        cert_count = options->vreader[i].cert_count;
+
+        ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys,
+                                      options->vreader[i].cert_count);
+        if (ret == PR_FALSE) {
+            continue;
+        }
+        cert_count = 0;
+        for (j = 0; j < options->vreader[i].cert_count; j++) {
+            /* we should have a better way of identifying certs than by
+             * nickname here */
+            CERTCertificate *cert = PK11_FindCertFromNickname(
+                                        options->vreader[i].cert_name[j],
+                                        NULL);
+            if (cert == NULL) {
+                continue;
+            }
+            certs[cert_count] = cert->derCert.data;
+            cert_len[cert_count] = cert->derCert.len;
+            keys[cert_count] = vcard_emul_make_key(slot, cert);
+            /* this is safe because the key is still holding a cert reference */
+            CERT_DestroyCertificate(cert);
+            cert_count++;
+        }
+        if (cert_count) {
+            VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len,
+                                                keys, cert_count);
+            vreader_insert_card(vreader, vcard);
+            vcard_emul_init_series(vreader, vcard);
+            /* allow insertion and removal of soft cards */
+            vreader_emul->saved_vcard = vcard_reference(vcard);
+            vcard_free(vcard);
+            vreader_free(vreader);
+            has_readers = PR_TRUE;
+        }
+    }
+
+    /* if we aren't suppose to use hw, skip looking up hardware tokens */
+    if (!options->use_hw) {
+        nss_emul_init = has_readers;
+        return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
+    }
+
+    /* make sure we have some PKCS #11 module loaded */
+    module_lock = SECMOD_GetDefaultModuleListLock();
+    module_list = SECMOD_GetDefaultModuleList();
+    need_coolkey_module = !has_readers;
+    SECMOD_GetReadLock(module_lock);
+    for (mlp = module_list; mlp; mlp = mlp->next) {
+        SECMODModule *module = mlp->module;
+        if (module_has_removable_hw_slots(module)) {
+            need_coolkey_module = PR_FALSE;
+            break;
+        }
+    }
+    SECMOD_ReleaseReadLock(module_lock);
+
+    if (need_coolkey_module) {
+        SECMODModule *module;
+        module = SECMOD_LoadUserModule(
+                    (char *)"library=libcoolkeypk11.so name=Coolkey",
+                    NULL, PR_FALSE);
+        if (module == NULL) {
+            return VCARD_EMUL_FAIL;
+        }
+        SECMOD_DestroyModule(module); /* free our reference, Module will still
+                                       * be on the list.
+                                       * until we destroy it */
+    }
+
+    /* now examine all the slots, finding which should be readers */
+    /* We should control this with options. For now we mirror out any
+     * removable hardware slot */
+    default_card_type = options->hw_card_type;
+    default_type_params = strdup(options->hw_type_params);
+
+    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;
+        }
+
+        for (i = 0; i < module->slotCount; i++) {
+            PK11SlotInfo *slot = module->slots[i];
+
+            /* only map removable HW slots */
+            if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) {
+                continue;
+            }
+            vreader_emul = vreader_emul_new(slot, options->hw_card_type,
+                                            options->hw_type_params);
+            vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
+                                  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);
+                vreader_insert_card(vreader, vcard);
+                vcard_emul_init_series(vreader, vcard);
+                vcard_free(vcard);
+            }
+        }
+        if (has_emul_slots) {
+            vcard_emul_new_event_thread(module);
+        }
+    }
+    SECMOD_ReleaseReadLock(module_lock);
+    nss_emul_init = has_readers;
+
+    return VCARD_EMUL_OK;
+}
+
+/* Recreate card insert events for all readers (user should
+ * deduce implied reader insert. perhaps do a reader insert as well?)
+ */
+void
+vcard_emul_replay_insertion_events(void)
+{
+    VReaderListEntry *current_entry;
+    VReaderListEntry *next_entry = NULL;
+    VReaderList *list = vreader_get_reader_list();
+
+    for (current_entry = vreader_list_get_first(list); current_entry;
+            current_entry = next_entry) {
+        VReader *vreader = vreader_list_get_reader(current_entry);
+        next_entry = vreader_list_get_next(current_entry);
+        vreader_queue_card_event(vreader);
+    }
+}
+
+/*
+ *  Silly little functions to help parsing our argument string
+ */
+static char *
+copy_string(const char *str, int str_len)
+{
+    char *new_str;
+
+    new_str = qemu_malloc(str_len+1);
+    memcpy(new_str, str, str_len);
+    new_str[str_len] = 0;
+    return new_str;
+}
+
+static int
+count_tokens(const char *str, char token, char token_end)
+{
+    int count = 0;
+
+    for (; *str; str++) {
+        if (*str == token) {
+            count++;
+        }
+        if (*str == token_end) {
+            break;
+        }
+    }
+    return count;
+}
+
+static const char *
+strip(const char *str)
+{
+    for (; *str && isspace(*str); str++) {
+    }
+    return str;
+}
+
+static const char *
+find_blank(const char *str)
+{
+    for (; *str && !isspace(*str); str++) {
+    }
+    return str;
+}
+
+
+/*
+ *  We really want to use some existing argument parsing library here. That
+ *  would give us a consistant look */
+static VCardEmulOptions options;
+#define READER_STEP 4
+
+VCardEmulOptions *
+vcard_emul_options(const char *args)
+{
+    int reader_count = 0;
+    VCardEmulOptions *opts;
+    char type_str[100];
+    int type_len;
+
+    /* Allow the future use of allocating the options structure on the fly */
+    memcpy(&options, &default_options, sizeof(options));
+    opts = &options;
+
+    do {
+        args = strip(args); /* strip off the leading spaces */
+        if (*args == ',') {
+            continue;
+        }
+        /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
+         *       cert_2,cert_3...) */
+        if (strncmp(args, "soft=", 5) == 0) {
+            const char *name;
+            const char *vname;
+            const char *type_params;
+            VCardEmulType type;
+            int name_length, vname_length, type_params_length, count, i;
+            VirtualReaderOptions *vreaderOpt = NULL;
+
+            args = strip(args + 5);
+            if (*args != '(') {
+                continue;
+            }
+            name = args;
+            args = strpbrk(args + 1, ",)");
+            if (*args == 0) {
+                break;
+            }
+            if (*args == ')') {
+                args++;
+                continue;
+            }
+            args = strip(args+1);
+            name_length = args - name - 2;
+            vname = args;
+            args = strpbrk(args + 1, ",)");
+            if (*args == 0) {
+                break;
+            }
+            if (*args == ')') {
+                args++;
+                continue;
+            }
+            vname_length = args - name - 2;
+            args = strip(args+1);
+            type_len = strpbrk(args, ",)") - args;
+            assert(sizeof(type_str) > type_len);
+            strncpy(type_str, args, type_len);
+            type_str[type_len] = 0;
+            type = vcard_emul_type_from_string(type_str);
+            args = strpbrk(args, ",)");
+            if (*args == 0) {
+                break;
+            }
+            if (*args == ')') {
+                args++;
+                continue;
+            }
+            args = strip(args++);
+            type_params = args;
+            args = strpbrk(args + 1, ",)");
+            if (*args == 0) {
+                break;
+            }
+            if (*args == ')') {
+                args++;
+                continue;
+            }
+            type_params_length = args - name;
+            args = strip(args++);
+            if (*args == 0) {
+                break;
+            }
+
+            if (opts->vreader_count >= reader_count) {
+                reader_count += READER_STEP;
+                vreaderOpt = realloc(opts->vreader,
+                                reader_count * sizeof(*vreaderOpt));
+                if (vreaderOpt == NULL) {
+                    return opts; /* we're done */
+                }
+            }
+            opts->vreader = vreaderOpt;
+            vreaderOpt = &vreaderOpt[opts->vreader_count];
+            vreaderOpt->name = copy_string(name, name_length);
+            vreaderOpt->vname = copy_string(vname, vname_length);
+            vreaderOpt->card_type = type;
+            vreaderOpt->type_params =
+                copy_string(type_params, type_params_length);
+            count = count_tokens(args, ',', ')');
+            vreaderOpt->cert_count = count;
+            vreaderOpt->cert_name = (char **)qemu_malloc(count*sizeof(char *));
+            for (i = 0; i < count; i++) {
+                const char *cert = args + 1;
+                args = strpbrk(args + 1, ",)");
+                vreaderOpt->cert_name[i] = copy_string(cert, args - cert);
+            }
+            if (*args == ')') {
+                args++;
+            }
+            opts->vreader_count++;
+        /* use_hw= */
+        } else if (strncmp(args, "use_hw=", 7) == 0) {
+            args = strip(args+7);
+            if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
+                opts->use_hw = PR_FALSE;
+            } else {
+                opts->use_hw = PR_TRUE;
+            }
+            args = find_blank(args);
+        /* hw_type= */
+        } else if (strncmp(args, "hw_type=", 8) == 0) {
+            args = strip(args+8);
+            opts->hw_card_type = vcard_emul_type_from_string(args);
+            args = find_blank(args);
+        /* hw_params= */
+        } else if (strncmp(args, "hw_params=", 10) == 0) {
+            const char *params;
+            args = strip(args+10);
+            params = args;
+            args = find_blank(args);
+            opts->hw_type_params = copy_string(params, args-params);
+        /* db="/data/base/path" */
+        } else if (strncmp(args, "db=", 3) == 0) {
+            const char *db;
+            args = strip(args+3);
+            if (*args != '"') {
+                continue;
+            }
+            args++;
+            db = args;
+            args = strpbrk(args, "\"\n");
+            opts->nss_db = copy_string(db, args-db);
+            if (*args != 0) {
+                args++;
+            }
+        } else {
+            args = find_blank(args);
+        }
+    } while (*args != 0);
+
+    return opts;
+}
+
+void
+vcard_emul_usage(void)
+{
+   fprintf(stderr,
+"emul args: comma separated list of the following arguments\n"
+" db={nss_database}               (default sql:/etc/pki/nssdb)\n"
+" use_hw=[yes|no]                 (default yes)\n"
+" hw_type={card_type_to_emulate}  (default CAC)\n"
+" hw_param={param_for_card}       (default \"\")\n"
+" soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
+"       {cert1},{cert2},{cert3}    (default none)\n"
+"\n"
+"  {nss_database}          The location of the NSS cert & key database\n"
+"  {card_type_to_emulate}  What card interface to present to the guest\n"
+"  {param_for_card}        Card interface specific parameters\n"
+"  {slot_name}             NSS slot that contains the certs\n"
+"  {vreader_name}          Virutal reader name to present to the guest\n"
+"  {certN}                 Nickname of the certificate n on the virtual card\n"
+"\n"
+"These parameters come as a single string separated by blanks or newlines."
+"\n"
+"Unless use_hw is set to no, all tokens that look like removable hardware\n"
+"tokens will be presented to the guest using the emulator specified by\n"
+"hw_type, and parameters of hw_param.\n"
+"\n"
+"If more one or more soft= parameters are specified, these readers will be\n"
+"presented to the guest\n");
+}
diff --git a/libcacard/vcard_emul_type.c b/libcacard/vcard_emul_type.c
new file mode 100644 (file)
index 0000000..59a1458
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  This file contains utility functions which abstract the different card
+ *  types.  The goal is that new card types can easily be added by simply
+ *  changing this file and vcard_emul_type.h. It is currently not a requirement
+ *  to dynamically add new card types.
+ *
+ * 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 <strings.h>
+#include "vcardt.h"
+#include "vcard_emul_type.h"
+#include "cac.h"
+
+VCardStatus vcard_init(VReader *vreader, VCard *vcard,
+                       VCardEmulType type, const char *params,
+                       unsigned char *const *cert, int cert_len[],
+                       VCardKey *key[], int cert_count)
+{
+    switch (type) {
+    case VCARD_EMUL_NONE:
+        break;
+    case VCARD_EMUL_CAC:
+        return cac_card_init(vreader, vcard, params,
+                             cert, cert_len, key,  cert_count);
+    /* add new ones here */
+    default:
+        break;
+    }
+    return VCARD_FAIL;
+}
+
+VCardEmulType vcard_emul_type_select(VReader *vreader)
+{
+#ifdef notdef
+    /* since there is only one emulator no need to call this function */
+    if (cac_is_cac_card(vreader) == VCARD_DONE) {
+        return VCARD_EMUL_CAC;
+    }
+#endif
+    /* return the default */
+    return VCARD_EMUL_CAC;
+}
+
+VCardEmulType vcard_emul_type_from_string(const char *type_string)
+{
+     if (strcasecmp(type_string, "CAC") == 0) {
+        return VCARD_EMUL_CAC;
+     }
+#ifdef USE_PASSTHRU
+     if (strcasecmp(type_string, "PASSTHRU") == 0) {
+        return VCARD_EMUL_PASSTHRU;
+     }
+#endif
+     return VCARD_EMUL_NONE;
+}
diff --git a/libcacard/vcard_emul_type.h b/libcacard/vcard_emul_type.h
new file mode 100644 (file)
index 0000000..0242f40
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  This header file abstracts the different card types. The goal is new card
+ *  types can easily be added by simply changing this file and
+ *  vcard_emul_type.c. It is currently not a requirement to dynamically add new
+ *  card types.
+ *
+ * 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.
+ */
+
+#ifndef VCARD_EMUL_TYPE_H
+#define VCARD_EMUL_TYPE_H 1
+#include "vcardt.h"
+#include "vreadert.h"
+
+/*
+ * types
+ */
+typedef enum {
+     VCARD_EMUL_NONE = 0,
+     VCARD_EMUL_CAC,
+     VCARD_EMUL_PASSTHRU
+} VCardEmulType;
+
+/* functions used by the rest of the emulator */
+VCardStatus vcard_init(VReader *vreader, VCard *vcard, VCardEmulType type,
+                       const char *params, unsigned char * const *cert,
+                       int cert_len[], VCardKey *key[], int cert_count);
+VCardEmulType vcard_emul_type_select(VReader *vreader);
+VCardEmulType vcard_emul_type_from_string(const char *type_string);
+
+#endif
diff --git a/libcacard/vcardt.h b/libcacard/vcardt.h
new file mode 100644 (file)
index 0000000..538bdde
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+#ifndef VCARDT_H
+#define VCARDT_H 1
+
+/*
+ * these should come from some common spice header file
+ */
+#include <assert.h>
+#ifndef MIN
+#define MIN(x, y) ((x) > (y) ? (y) : (x))
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+typedef struct VCardStruct VCard;
+typedef struct VCardAPDUStruct VCardAPDU;
+typedef struct VCardResponseStruct VCardResponse;
+typedef struct VCardBufferResponseStruct VCardBufferResponse;
+typedef struct VCardAppletStruct VCardApplet;
+typedef struct VCardAppletPrivateStruct VCardAppletPrivate;
+typedef struct VCardKeyStruct VCardKey;  /* opaque */
+typedef struct VCardEmulStruct VCardEmul;
+
+#define MAX_CHANNEL 4
+
+/* create an ATR with appropriate historical bytes */
+#define VCARD_ATR_PREFIX(size) 0x3b, 0x66+(size), 0x00, 0xff, \
+                               'V', 'C', 'A', 'R', 'D', '_'
+
+
+typedef enum {
+    VCARD_DONE,
+    VCARD_NEXT,
+    VCARD_FAIL
+} VCardStatus;
+
+typedef enum {
+    VCARD_FILE_SYSTEM,
+    VCARD_VM,
+    VCARD_DIRECT
+} VCardType;
+
+typedef enum {
+    VCARD_POWER_ON,
+    VCARD_POWER_OFF
+} VCardPower;
+
+typedef VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu,
+                                        VCardResponse **response);
+typedef VCardStatus (*VCardResetApplet)(VCard *card, int channel);
+typedef void (*VCardAppletPrivateFree) (VCardAppletPrivate *);
+typedef void (*VCardEmulFree) (VCardEmul *);
+typedef void (*VCardGetAtr) (VCard *, unsigned char *atr, int *atr_len);
+
+struct VCardBufferResponseStruct {
+    unsigned char *buffer;
+    int buffer_len;
+    unsigned char *current;
+    int len;
+};
+
+#endif
diff --git a/libcacard/vevent.h b/libcacard/vevent.h
new file mode 100644 (file)
index 0000000..38c3482
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+#ifndef EVENT_H
+#define EVENT_H 1
+#include "eventt.h"
+#include "vreadert.h"
+#include "vcardt.h"
+
+VEvent *vevent_new(VEventType type, VReader *reader, VCard *card);
+void vevent_delete(VEvent *);
+
+/*
+ * VEvent queueing services
+ */
+void vevent_queue_vevent(VEvent *);
+void vevent_queue_init(void);
+
+/*
+ *  VEvent dequeing services
+ */
+VEvent *vevent_wait_next_vevent(void);
+VEvent *vevent_get_next_vevent(void);
+
+
+#endif
diff --git a/libcacard/vreader.c b/libcacard/vreader.c
new file mode 100644 (file)
index 0000000..4a0125b
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * emulate the reader
+ *
+ * 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 "qemu-common.h"
+#include "qemu-thread.h"
+
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816.h"
+#include "vreader.h"
+#include "vevent.h"
+
+struct VReaderStruct {
+    int    reference_count;
+    VCard *card;
+    char *name;
+    vreader_id_t id;
+    QemuMutex lock;
+    VReaderEmul  *reader_private;
+    VReaderEmulFree reader_private_free;
+};
+
+/* manage locking */
+static inline void
+vreader_lock(VReader *reader)
+{
+    qemu_mutex_lock(&reader->lock);
+}
+
+static inline void
+vreader_unlock(VReader *reader)
+{
+    qemu_mutex_unlock(&reader->lock);
+}
+
+/*
+ * vreader constructor
+ */
+VReader *
+vreader_new(const char *name, VReaderEmul *private,
+            VReaderEmulFree private_free)
+{
+    VReader *reader;
+
+    reader = (VReader *)qemu_malloc(sizeof(VReader));
+    qemu_mutex_init(&reader->lock);
+    reader->reference_count = 1;
+    reader->name = name ? strdup(name) : NULL;
+    reader->card = NULL;
+    reader->id = (vreader_id_t)-1;
+    reader->reader_private = private;
+    reader->reader_private_free = private_free;
+    return reader;
+}
+
+/* get a reference */
+VReader*
+vreader_reference(VReader *reader)
+{
+    if (reader == NULL) {
+        return NULL;
+    }
+    vreader_lock(reader);
+    reader->reference_count++;
+    vreader_unlock(reader);
+    return reader;
+}
+
+/* free a reference */
+void
+vreader_free(VReader *reader)
+{
+    if (reader == NULL) {
+        return;
+    }
+    vreader_lock(reader);
+    if (reader->reference_count-- > 1) {
+        vreader_unlock(reader);
+        return;
+    }
+    vreader_unlock(reader);
+    if (reader->card) {
+        vcard_free(reader->card);
+    }
+    if (reader->name) {
+        qemu_free(reader->name);
+    }
+    if (reader->reader_private_free) {
+        reader->reader_private_free(reader->reader_private);
+    }
+    qemu_free(reader);
+    return;
+}
+
+static VCard *
+vreader_get_card(VReader *reader)
+{
+    VCard *card;
+
+    vreader_lock(reader);
+    card = vcard_reference(reader->card);
+    vreader_unlock(reader);
+    return card;
+}
+
+VReaderStatus
+vreader_card_is_present(VReader *reader)
+{
+    VCard *card = vreader_get_card(reader);
+
+    if (card == NULL) {
+        return VREADER_NO_CARD;
+    }
+    vcard_free(card);
+    return VREADER_OK;
+}
+
+vreader_id_t
+vreader_get_id(VReader *reader)
+{
+    if (reader == NULL) {
+        return (vreader_id_t)-1;
+    }
+    return reader->id;
+}
+
+VReaderStatus
+vreader_set_id(VReader *reader, vreader_id_t id)
+{
+    if (reader == NULL) {
+        return VREADER_NO_CARD;
+    }
+    reader->id = id;
+    return VREADER_OK;
+}
+
+const char *
+vreader_get_name(VReader *reader)
+{
+    if (reader == NULL) {
+        return NULL;
+    }
+    return reader->name;
+}
+
+VReaderEmul *
+vreader_get_private(VReader *reader)
+{
+    return reader->reader_private;
+}
+
+static VReaderStatus
+vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len)
+{
+    VCard *card = vreader_get_card(reader);
+
+    if (card == NULL) {
+        return VREADER_NO_CARD;
+    }
+    /*
+     * clean up our state
+     */
+    vcard_reset(card, power);
+    if (atr) {
+        vcard_get_atr(card, atr, len);
+    }
+    vcard_free(card); /* free our reference */
+    return VREADER_OK;
+}
+
+VReaderStatus
+vreader_power_on(VReader *reader, unsigned char *atr, int *len)
+{
+    return vreader_reset(reader, VCARD_POWER_ON, atr, len);
+}
+
+VReaderStatus
+vreader_power_off(VReader *reader)
+{
+    return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0);
+}
+
+
+VReaderStatus
+vreader_xfr_bytes(VReader *reader,
+                  unsigned char *send_buf, int send_buf_len,
+                  unsigned char *receive_buf, int *receive_buf_len)
+{
+    VCardAPDU *apdu;
+    VCardResponse *response = NULL;
+    VCardStatus card_status;
+    unsigned short status;
+    VCard *card = vreader_get_card(reader);
+
+    if (card == NULL) {
+        return VREADER_NO_CARD;
+    }
+
+    apdu = vcard_apdu_new(send_buf, send_buf_len, &status);
+    if (apdu == NULL) {
+        response = vcard_make_response(status);
+        card_status = VCARD_DONE;
+    } else {
+        card_status = vcard_process_apdu(card, apdu, &response);
+    }
+    assert(card_status == VCARD_DONE);
+    if (card_status == VCARD_DONE) {
+        int size = MIN(*receive_buf_len, response->b_total_len);
+        memcpy(receive_buf, response->b_data, size);
+        *receive_buf_len = size;
+    }
+    vcard_response_delete(response);
+    vcard_apdu_delete(apdu);
+    vcard_free(card); /* free our reference */
+    return VREADER_OK;
+}
+
+struct VReaderListStruct {
+    VReaderListEntry *head;
+    VReaderListEntry *tail;
+};
+
+struct VReaderListEntryStruct {
+    VReaderListEntry *next;
+    VReaderListEntry *prev;
+    VReader *reader;
+};
+
+
+static VReaderListEntry *
+vreader_list_entry_new(VReader *reader)
+{
+    VReaderListEntry *new_reader_list_entry;
+
+    new_reader_list_entry = (VReaderListEntry *)
+                               qemu_malloc(sizeof(VReaderListEntry));
+    new_reader_list_entry->next = NULL;
+    new_reader_list_entry->prev = NULL;
+    new_reader_list_entry->reader = vreader_reference(reader);
+    return new_reader_list_entry;
+}
+
+static void
+vreader_list_entry_delete(VReaderListEntry *entry)
+{
+    if (entry == NULL) {
+        return;
+    }
+    vreader_free(entry->reader);
+    qemu_free(entry);
+}
+
+
+static VReaderList *
+vreader_list_new(void)
+{
+    VReaderList *new_reader_list;
+
+    new_reader_list = (VReaderList *)qemu_malloc(sizeof(VReaderList));
+    new_reader_list->head = NULL;
+    new_reader_list->tail = NULL;
+    return new_reader_list;
+}
+
+void
+vreader_list_delete(VReaderList *list)
+{
+    VReaderListEntry *current_entry;
+    VReaderListEntry *next_entry = NULL;
+    for (current_entry = vreader_list_get_first(list); current_entry;
+         current_entry = next_entry) {
+        next_entry = vreader_list_get_next(current_entry);
+        vreader_list_entry_delete(current_entry);
+    }
+    list->head = NULL;
+    list->tail = NULL;
+    qemu_free(list);
+}
+
+
+VReaderListEntry *
+vreader_list_get_first(VReaderList *list)
+{
+    return list ? list->head : NULL;
+}
+
+VReaderListEntry *
+vreader_list_get_next(VReaderListEntry *current)
+{
+    return current ? current->next : NULL;
+}
+
+VReader *
+vreader_list_get_reader(VReaderListEntry *entry)
+{
+    return entry ? vreader_reference(entry->reader) : NULL;
+}
+
+static void
+vreader_queue(VReaderList *list, VReaderListEntry *entry)
+{
+    if (entry == NULL) {
+        return;
+    }
+    entry->next = NULL;
+    entry->prev = list->tail;
+    if (list->head) {
+        list->tail->next = entry;
+    } else {
+        list->head = entry;
+    }
+    list->tail = entry;
+}
+
+static void
+vreader_dequeue(VReaderList *list, VReaderListEntry *entry)
+{
+    if (entry == NULL) {
+        return;
+    }
+    if (entry->next == NULL) {
+        list->tail = entry->prev;
+    } else if (entry->prev == NULL) {
+        list->head = entry->next;
+    } else {
+        entry->prev->next = entry->next;
+        entry->next->prev = entry->prev;
+    }
+    if ((list->tail == NULL) || (list->head == NULL)) {
+        list->head = list->tail = NULL;
+    }
+    entry->next = entry->prev = NULL;
+}
+
+static VReaderList *vreader_list;
+static QemuMutex vreader_list_mutex;
+
+static void
+vreader_list_init(void)
+{
+    vreader_list = vreader_list_new();
+    qemu_mutex_init(&vreader_list_mutex);
+}
+
+static void
+vreader_list_lock(void)
+{
+    qemu_mutex_lock(&vreader_list_mutex);
+}
+
+static void
+vreader_list_unlock(void)
+{
+    qemu_mutex_unlock(&vreader_list_mutex);
+}
+
+static VReaderList *
+vreader_copy_list(VReaderList *list)
+{
+    VReaderList *new_list = NULL;
+    VReaderListEntry *current_entry = NULL;
+
+    new_list = vreader_list_new();
+    if (new_list == NULL) {
+        return NULL;
+    }
+    for (current_entry = vreader_list_get_first(list); current_entry;
+         current_entry = vreader_list_get_next(current_entry)) {
+        VReader *reader = vreader_list_get_reader(current_entry);
+        VReaderListEntry *new_entry = vreader_list_entry_new(reader);
+
+        vreader_free(reader);
+        vreader_queue(new_list, new_entry);
+    }
+    return new_list;
+}
+
+VReaderList *
+vreader_get_reader_list(void)
+{
+    VReaderList *new_reader_list;
+
+    vreader_list_lock();
+    new_reader_list = vreader_copy_list(vreader_list);
+    vreader_list_unlock();
+    return new_reader_list;
+}
+
+VReader *
+vreader_get_reader_by_id(vreader_id_t id)
+{
+    VReader *reader = NULL;
+    VReaderListEntry *current_entry = NULL;
+
+    if (id == (vreader_id_t) -1) {
+        return NULL;
+    }
+
+    vreader_list_lock();
+    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
+            current_entry = vreader_list_get_next(current_entry)) {
+        VReader *creader = vreader_list_get_reader(current_entry);
+        if (creader->id == id) {
+            reader = creader;
+            break;
+        }
+        vreader_free(creader);
+    }
+    vreader_list_unlock();
+    return reader;
+}
+
+VReader *
+vreader_get_reader_by_name(const char *name)
+{
+    VReader *reader = NULL;
+    VReaderListEntry *current_entry = NULL;
+
+    vreader_list_lock();
+    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
+            current_entry = vreader_list_get_next(current_entry)) {
+        VReader *creader = vreader_list_get_reader(current_entry);
+        if (strcmp(creader->name, name) == 0) {
+            reader = creader;
+            break;
+        }
+        vreader_free(creader);
+    }
+    vreader_list_unlock();
+    return reader;
+}
+
+/* called from card_emul to initialize the readers */
+VReaderStatus
+vreader_add_reader(VReader *reader)
+{
+    VReaderListEntry *reader_entry;
+
+    reader_entry = vreader_list_entry_new(reader);
+    if (reader_entry == NULL) {
+        return VREADER_OUT_OF_MEMORY;
+    }
+    vreader_list_lock();
+    vreader_queue(vreader_list, reader_entry);
+    vreader_list_unlock();
+    vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL));
+    return VREADER_OK;
+}
+
+
+VReaderStatus
+vreader_remove_reader(VReader *reader)
+{
+    VReaderListEntry *current_entry;
+
+    vreader_list_lock();
+    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
+         current_entry = vreader_list_get_next(current_entry)) {
+        if (current_entry->reader == reader) {
+            break;
+        }
+    }
+    vreader_dequeue(vreader_list, current_entry);
+    vreader_list_unlock();
+    vreader_list_entry_delete(current_entry);
+    vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL));
+    return VREADER_OK;
+}
+
+/*
+ * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader
+ * state. Separated from vreader_insert_card to allow replaying events
+ * for a given state.
+ */
+void
+vreader_queue_card_event(VReader *reader)
+{
+    vevent_queue_vevent(vevent_new(
+        reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader,
+        reader->card));
+}
+
+/*
+ * insert/remove a new card. for removal, card == NULL
+ */
+VReaderStatus
+vreader_insert_card(VReader *reader, VCard *card)
+{
+    vreader_lock(reader);
+    if (reader->card) {
+        /* decrement reference count */
+        vcard_free(reader->card);
+        reader->card = NULL;
+    }
+    reader->card = vcard_reference(card);
+    vreader_unlock(reader);
+    vreader_queue_card_event(reader);
+    return VREADER_OK;
+}
+
+/*
+ * initialize all the static reader structures
+ */
+void
+vreader_init(void)
+{
+    vreader_list_init();
+}
+
diff --git a/libcacard/vreader.h b/libcacard/vreader.h
new file mode 100644 (file)
index 0000000..ec20421
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef VREADER_H
+#define VREADER_H 1
+
+#include "eventt.h"
+#include "vreadert.h"
+#include "vcardt.h"
+
+/*
+ * calls for reader front end
+ */
+VReaderStatus vreader_power_on(VReader *reader, unsigned char *atr, int *len);
+VReaderStatus vreader_power_off(VReader *reader);
+VReaderStatus vreader_xfr_bytes(VReader *reader, unsigned char *send_buf,
+                                int send_buf_len, unsigned char *receive_buf,
+                                int *receive_buf_len);
+
+/* constructor */
+VReader *vreader_new(const char *readerName, VReaderEmul *emul_private,
+                     VReaderEmulFree private_free);
+/* get a new reference to a reader */
+VReader *vreader_reference(VReader *reader);
+/* "destructor" (readers are reference counted) */
+void vreader_free(VReader *reader);
+
+/* accessors */
+VReaderEmul *vreader_get_private(VReader *);
+VReaderStatus vreader_card_is_present(VReader *reader);
+void vreader_queue_card_event(VReader *reader);
+const char *vreader_get_name(VReader *reader);
+vreader_id_t vreader_get_id(VReader *reader);
+VReaderStatus vreader_set_id(VReader *reader, vreader_id_t id);
+
+/* list operations */
+VReaderList *vreader_get_reader_list(void);
+void vreader_list_delete(VReaderList *list);
+VReader *vreader_list_get_reader(VReaderListEntry *entry);
+VReaderListEntry *vreader_list_get_first(VReaderList *list);
+VReaderListEntry *vreader_list_get_next(VReaderListEntry *list);
+VReader *vreader_get_reader_by_id(vreader_id_t id);
+VReader *vreader_get_reader_by_name(const char *name);
+
+/*
+ * list tools for vcard_emul
+ */
+void vreader_init(void);
+VReaderStatus vreader_add_reader(VReader *reader);
+VReaderStatus vreader_remove_reader(VReader *reader);
+VReaderStatus vreader_insert_card(VReader *reader, VCard *card);
+
+#endif
diff --git a/libcacard/vreadert.h b/libcacard/vreadert.h
new file mode 100644 (file)
index 0000000..f97e0a7
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#ifndef VREADERT_H
+#define VREADERT_H 1
+
+typedef enum {
+    VREADER_OK = 0,
+    VREADER_NO_CARD,
+    VREADER_OUT_OF_MEMORY
+} VReaderStatus;
+
+typedef unsigned int vreader_id_t;
+typedef struct VReaderStruct VReader;
+typedef struct VReaderListStruct VReaderList;
+typedef struct VReaderListEntryStruct VReaderListEntry;
+
+typedef struct VReaderEmulStruct VReaderEmul;
+typedef void (*VReaderEmulFree)(VReaderEmul *);
+
+#endif
+
diff --git a/libcacard/vscard_common.h b/libcacard/vscard_common.h
new file mode 100644 (file)
index 0000000..bebd52d
--- /dev/null
@@ -0,0 +1,178 @@
+/* Virtual Smart Card protocol definition
+ *
+ * This protocol is between a host using virtual smart card readers,
+ * and a client providing the smart cards, perhaps by emulating them or by
+ * access to real cards.
+ *
+ * Definitions for this protocol:
+ *  Host   - user of the card
+ *  Client - owner of the card
+ *
+ * The current implementation passes the raw APDU's from 7816 and additionally
+ * contains messages to setup and teardown readers, handle insertion and
+ * removal of cards, negotiate the protocol via capabilities and provide
+ * for error responses.
+ *
+ * Copyright (c) 2011 Red Hat.
+ *
+ * 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.
+ */
+
+#ifndef VSCARD_COMMON_H
+#define VSCARD_COMMON_H
+
+#include <stdint.h>
+
+#define VERSION_MAJOR_BITS 11
+#define VERSION_MIDDLE_BITS 11
+#define VERSION_MINOR_BITS 10
+
+#define MAKE_VERSION(major, middle, minor) \
+     ((major  << (VERSION_MINOR_BITS + VERSION_MIDDLE_BITS)) \
+      | (middle <<  VERSION_MINOR_BITS) \
+      | (minor))
+
+/*
+ * IMPORTANT NOTE on VERSION
+ *
+ * The version below MUST be changed whenever a change in this file is made.
+ *
+ * The last digit, the minor, is for bug fix changes only.
+ *
+ * The middle digit is for backward / forward compatible changes, updates
+ * to the existing messages, addition of fields.
+ *
+ * The major digit is for a breaking change of protocol, presumably
+ * something that cannot be accomodated with the existing protocol.
+ */
+
+#define VSCARD_VERSION MAKE_VERSION(0, 0, 2)
+
+typedef enum VSCMsgType {
+    VSC_Init = 1,
+    VSC_Error,
+    VSC_ReaderAdd,
+    VSC_ReaderRemove,
+    VSC_ATR,
+    VSC_CardRemove,
+    VSC_APDU,
+    VSC_Flush,
+    VSC_FlushComplete
+} VSCMsgType;
+
+typedef enum VSCErrorCode {
+    VSC_SUCCESS = 0,
+    VSC_GENERAL_ERROR = 1,
+    VSC_CANNOT_ADD_MORE_READERS,
+    VSC_CARD_ALREAY_INSERTED,
+} VSCErrorCode;
+
+#define VSCARD_UNDEFINED_READER_ID  0xffffffff
+#define VSCARD_MINIMAL_READER_ID    0
+
+#define VSCARD_MAGIC (*(uint32_t *)"VSCD")
+
+/*
+ * Header
+ * Each message starts with the header.
+ * type - message type
+ * reader_id - used by messages that are reader specific
+ * length - length of payload (not including header, i.e. zero for
+ *  messages containing empty payloads)
+ */
+typedef struct VSCMsgHeader {
+    uint32_t   type;
+    uint32_t   reader_id;
+    uint32_t   length;
+    uint8_t    data[0];
+} VSCMsgHeader;
+
+/*
+ * VSCMsgInit               Client <-> Host
+ * Client sends it on connection, with its own capabilities.
+ * Host replies with VSCMsgInit filling in its capabilities.
+ *
+ * It is not meant to be used for negotiation, i.e. sending more then
+ * once from any side, but could be used for that in the future.
+ */
+typedef struct VSCMsgInit {
+    uint32_t   magic;
+    uint32_t   version;
+    uint32_t   capabilities[1]; /* receiver must check length,
+                                   array may grow in the future*/
+} VSCMsgInit;
+
+/*
+ * VSCMsgError              Client <-> Host
+ * This message is a response to any of:
+ *  Reader Add
+ *  Reader Remove
+ *  Card Remove
+ * If the operation was successful then VSC_SUCCESS
+ * is returned, other wise a specific error code.
+ */
+typedef struct VSCMsgError {
+    uint32_t   code;
+} VSCMsgError;
+
+/*
+ * VSCMsgReaderAdd          Client -> Host
+ * Host replies with allocated reader id in VSCMsgError with code==SUCCESS.
+ *
+ * name - name of the reader on client side, UTF-8 encoded. Only used
+ *  for client presentation (may be translated to the device presented to the
+ *  guest), protocol wise only reader_id is important.
+ */
+typedef struct VSCMsgReaderAdd {
+    uint8_t    name[0];
+} VSCMsgReaderAdd;
+
+/*
+ * VSCMsgReaderRemove       Client -> Host
+ * The client's reader has been removed.
+ */
+typedef struct VSCMsgReaderRemove {
+} VSCMsgReaderRemove;
+
+/*
+ * VSCMsgATR                Client -> Host
+ * Answer to reset. Sent for card insertion or card reset. The reset/insertion
+ * happens on the client side, they do not require any action from the host.
+ */
+typedef struct VSCMsgATR {
+    uint8_t     atr[0];
+} VSCMsgATR;
+
+/*
+ * VSCMsgCardRemove         Client -> Host
+ * The client card has been removed.
+ */
+typedef struct VSCMsgCardRemove {
+} VSCMsgCardRemove;
+
+/*
+ * VSCMsgAPDU               Client <-> Host
+ * Main reason of existance. Transfer a single APDU in either direction.
+ */
+typedef struct VSCMsgAPDU {
+    uint8_t    data[0];
+} VSCMsgAPDU;
+
+/*
+ * VSCMsgFlush               Host -> Client
+ * Request client to send a FlushComplete message when it is done
+ * servicing all outstanding APDUs
+ */
+typedef struct VSCMsgFlush {
+} VSCMsgFlush;
+
+/*
+ * VSCMsgFlush               Client -> Host
+ * Client response to Flush after all APDUs have been processed and
+ * responses sent.
+ */
+typedef struct VSCMsgFlushComplete {
+} VSCMsgFlushComplete;
+
+#endif /* VSCARD_COMMON_H */
diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
new file mode 100644 (file)
index 0000000..ce33f5a
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * Tester for VSCARD protocol, client side.
+ *
+ * Can be used with ccid-card-passthru.
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * 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 <netdb.h>
+
+#include "qemu-common.h"
+#include "qemu-thread.h"
+#include "qemu_socket.h"
+
+#include "vscard_common.h"
+
+#include "vreader.h"
+#include "vcard_emul.h"
+#include "vevent.h"
+
+int verbose;
+
+int sock;
+
+static void
+print_byte_array(
+    uint8_t *arrBytes,
+    unsigned int nSize
+) {
+    int i;
+    for (i = 0; i < nSize; i++) {
+        printf("%02X ", arrBytes[i]);
+    }
+    printf("\n");
+}
+
+static void
+print_usage(void) {
+    printf("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] "
+            "<host> <port>\n",
+#ifdef USE_PASSTHRU
+    " -p");
+    printf(" -p use passthrough mode\n");
+#else
+   "");
+#endif
+    vcard_emul_usage();
+}
+
+static QemuMutex write_lock;
+
+static int
+send_msg(
+    VSCMsgType type,
+    uint32_t reader_id,
+    const void *msg,
+    unsigned int length
+) {
+    int rv;
+    VSCMsgHeader mhHeader;
+
+    qemu_mutex_lock(&write_lock);
+
+    if (verbose > 10) {
+        printf("sending type=%d id=%d, len =%d (0x%x)\n",
+               type, reader_id, length, length);
+    }
+
+    mhHeader.type = htonl(type);
+    mhHeader.reader_id = 0;
+    mhHeader.length = htonl(length);
+    rv = write(sock, &mhHeader, sizeof(mhHeader));
+    if (rv < 0) {
+        /* Error */
+        fprintf(stderr, "write header error\n");
+        close(sock);
+        qemu_mutex_unlock(&write_lock);
+        return 16;
+    }
+    rv = write(sock, msg, length);
+    if (rv < 0) {
+        /* Error */
+        fprintf(stderr, "write error\n");
+        close(sock);
+        qemu_mutex_unlock(&write_lock);
+        return 16;
+    }
+    qemu_mutex_unlock(&write_lock);
+
+    return 0;
+}
+
+static VReader *pending_reader;
+static QemuMutex pending_reader_lock;
+static QemuCond pending_reader_condition;
+
+#define MAX_ATR_LEN 40
+static void *
+event_thread(void *arg)
+{
+    unsigned char atr[MAX_ATR_LEN];
+    int atr_len = MAX_ATR_LEN;
+    VEvent *event = NULL;
+    unsigned int reader_id;
+
+
+    while (1) {
+        const char *reader_name;
+
+        event = vevent_wait_next_vevent();
+        if (event == NULL) {
+            break;
+        }
+        reader_id = vreader_get_id(event->reader);
+        if (reader_id == VSCARD_UNDEFINED_READER_ID &&
+            event->type != VEVENT_READER_INSERT) {
+            /* ignore events from readers qemu has rejected */
+            /* if qemu is still deciding on this reader, wait to see if need to
+             * forward this event */
+            qemu_mutex_lock(&pending_reader_lock);
+            if (!pending_reader || (pending_reader != event->reader)) {
+                /* wasn't for a pending reader, this reader has already been
+                 * rejected by qemu */
+                qemu_mutex_unlock(&pending_reader_lock);
+                vevent_delete(event);
+                continue;
+            }
+            /* this reader hasn't been told it's status from qemu yet, wait for
+             * that status */
+            while (pending_reader != NULL) {
+                qemu_cond_wait(&pending_reader_condition, &pending_reader_lock);
+            }
+            qemu_mutex_unlock(&pending_reader_lock);
+            /* now recheck the id */
+            reader_id = vreader_get_id(event->reader);
+            if (reader_id == VSCARD_UNDEFINED_READER_ID) {
+                /* this reader was rejected */
+                vevent_delete(event);
+                continue;
+            }
+            /* reader was accepted, now forward the event */
+        }
+        switch (event->type) {
+        case VEVENT_READER_INSERT:
+            /* tell qemu to insert a new CCID reader */
+            /* wait until qemu has responded to our first reader insert
+             * before we send a second. That way we won't confuse the responses
+             * */
+            qemu_mutex_lock(&pending_reader_lock);
+            while (pending_reader != NULL) {
+                qemu_cond_wait(&pending_reader_condition, &pending_reader_lock);
+            }
+            pending_reader = vreader_reference(event->reader);
+            qemu_mutex_unlock(&pending_reader_lock);
+            reader_name = vreader_get_name(event->reader);
+            if (verbose > 10) {
+                printf(" READER INSERT: %s\n", reader_name);
+            }
+            send_msg(VSC_ReaderAdd,
+                reader_id, /* currerntly VSCARD_UNDEFINED_READER_ID */
+                NULL, 0 /* TODO reader_name, strlen(reader_name) */);
+            break;
+        case VEVENT_READER_REMOVE:
+            /* future, tell qemu that an old CCID reader has been removed */
+            if (verbose > 10) {
+                printf(" READER REMOVE: %d\n", reader_id);
+            }
+            send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
+            break;
+        case VEVENT_CARD_INSERT:
+            /* get the ATR (intended as a response to a power on from the
+             * reader */
+            atr_len = MAX_ATR_LEN;
+            vreader_power_on(event->reader, atr, &atr_len);
+            /* ATR call functions as a Card Insert event */
+            if (verbose > 10) {
+                printf(" CARD INSERT %d: ", reader_id);
+                print_byte_array(atr, atr_len);
+            }
+            send_msg(VSC_ATR, reader_id, atr, atr_len);
+            break;
+        case VEVENT_CARD_REMOVE:
+            /* Card removed */
+            if (verbose > 10) {
+                printf(" CARD REMOVE %d:\n", reader_id);
+            }
+            send_msg(VSC_CardRemove, reader_id, NULL, 0);
+            break;
+        default:
+            break;
+        }
+        vevent_delete(event);
+    }
+    return NULL;
+}
+
+
+static unsigned int
+get_id_from_string(char *string, unsigned int default_id)
+{
+    unsigned int id = atoi(string);
+
+    /* don't accidentally swith to zero because no numbers have been supplied */
+    if ((id == 0) && *string != '0') {
+        return default_id;
+    }
+    return id;
+}
+
+static void
+do_command(void)
+{
+    char inbuf[255];
+    char *string;
+    VCardEmulError error;
+    static unsigned int default_reader_id;
+    unsigned int reader_id;
+    VReader *reader = NULL;
+
+    reader_id = default_reader_id;
+    string = fgets(inbuf, sizeof(inbuf), stdin);
+    if (string != NULL) {
+        if (strncmp(string, "exit", 4) == 0) {
+            /* remove all the readers */
+            VReaderList *list = vreader_get_reader_list();
+            VReaderListEntry *reader_entry;
+            printf("Active Readers:\n");
+            for (reader_entry = vreader_list_get_first(list); reader_entry;
+                 reader_entry = vreader_list_get_next(reader_entry)) {
+                VReader *reader = vreader_list_get_reader(reader_entry);
+                vreader_id_t reader_id;
+                reader_id = vreader_get_id(reader);
+                if (reader_id == -1) {
+                    continue;
+                }
+                /* be nice and signal card removal first (qemu probably should
+                 * do this itself) */
+                if (vreader_card_is_present(reader) == VREADER_OK) {
+                    send_msg(VSC_CardRemove, reader_id, NULL, 0);
+                }
+                send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
+            }
+            exit(0);
+        } else if (strncmp(string, "insert", 6) == 0) {
+            if (string[6] == ' ') {
+                reader_id = get_id_from_string(&string[7], reader_id);
+            }
+            reader = vreader_get_reader_by_id(reader_id);
+            if (reader != NULL) {
+                error = vcard_emul_force_card_insert(reader);
+                printf("insert %s, returned %d\n",
+                       reader ? vreader_get_name(reader)
+                       : "invalid reader", error);
+            } else {
+                printf("no reader by id %d found\n", reader_id);
+            }
+        } else if (strncmp(string, "remove", 6) == 0) {
+            if (string[6] == ' ') {
+                reader_id = get_id_from_string(&string[7], reader_id);
+            }
+            reader = vreader_get_reader_by_id(reader_id);
+            if (reader != NULL) {
+                error = vcard_emul_force_card_remove(reader);
+                printf("remove %s, returned %d\n",
+                        reader ? vreader_get_name(reader)
+                        : "invalid reader", error);
+            } else {
+                printf("no reader by id %d found\n", reader_id);
+            }
+        } else if (strncmp(string, "select", 6) == 0) {
+            if (string[6] == ' ') {
+                reader_id = get_id_from_string(&string[7],
+                                               VSCARD_UNDEFINED_READER_ID);
+            }
+            if (reader_id != VSCARD_UNDEFINED_READER_ID) {
+                reader = vreader_get_reader_by_id(reader_id);
+            }
+            if (reader) {
+                printf("Selecting reader %d, %s\n", reader_id,
+                        vreader_get_name(reader));
+                default_reader_id = reader_id;
+            } else {
+                printf("Reader with id %d not found\n", reader_id);
+            }
+        } else if (strncmp(string, "debug", 5) == 0) {
+            if (string[5] == ' ') {
+                verbose = get_id_from_string(&string[6], 0);
+            }
+            printf("debug level = %d\n", verbose);
+        } else if (strncmp(string, "list", 4) == 0) {
+            VReaderList *list = vreader_get_reader_list();
+            VReaderListEntry *reader_entry;
+            printf("Active Readers:\n");
+            for (reader_entry = vreader_list_get_first(list); reader_entry;
+                 reader_entry = vreader_list_get_next(reader_entry)) {
+                VReader *reader = vreader_list_get_reader(reader_entry);
+                vreader_id_t reader_id;
+                reader_id = vreader_get_id(reader);
+                if (reader_id == -1) {
+                    continue;
+                }
+                printf("%3d %s %s\n", reader_id,
+                       vreader_card_is_present(reader) == VREADER_OK ?
+                       "CARD_PRESENT" : "            ",
+                       vreader_get_name(reader));
+            }
+            printf("Inactive Readers:\n");
+            for (reader_entry = vreader_list_get_first(list); reader_entry;
+                 reader_entry = vreader_list_get_next(reader_entry)) {
+                VReader *reader = vreader_list_get_reader(reader_entry);
+                vreader_id_t reader_id;
+                reader_id = vreader_get_id(reader);
+                if (reader_id != -1) {
+                    continue;
+                }
+
+                printf("INA %s %s\n",
+                       vreader_card_is_present(reader) == VREADER_OK ?
+                       "CARD_PRESENT" : "            ",
+                       vreader_get_name(reader));
+            }
+        } else if (*string != 0) {
+            printf("valid commands:\n");
+            printf("insert [reader_id]\n");
+            printf("remove [reader_id]\n");
+            printf("select reader_id\n");
+            printf("list\n");
+            printf("debug [level]\n");
+            printf("exit\n");
+        }
+    }
+    vreader_free(reader);
+    printf("> ");
+    fflush(stdout);
+}
+
+
+#define APDUBufSize 270
+
+/* just for ease of parsing command line arguments. */
+#define MAX_CERTS 100
+
+static int
+connect_to_qemu(
+    const char *host,
+    const char *port
+) {
+    struct addrinfo hints;
+    struct addrinfo *server;
+    int ret;
+
+    sock = qemu_socket(AF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+        /* Error */
+        fprintf(stderr, "Error opening socket!\n");
+    }
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = 0;
+    hints.ai_protocol = 0;          /* Any protocol */
+
+    ret = getaddrinfo(host, port, &hints, &server);
+
+    if (ret != 0) {
+        /* Error */
+        fprintf(stderr, "getaddrinfo failed\n");
+        return 5;
+    }
+
+    if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) {
+        /* Error */
+        fprintf(stderr, "Could not connect\n");
+        return 5;
+    }
+    if (verbose) {
+        printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
+    }
+    return sock;
+}
+
+static int on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming)
+{
+    uint32_t *capabilities = (incoming->capabilities);
+    int num_capabilities =
+        1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
+    int i;
+    int rv;
+    pthread_t thread_id;
+
+    incoming->version = ntohl(incoming->version);
+    if (incoming->version != VSCARD_VERSION) {
+        if (verbose > 0) {
+            printf("warning: host has version %d, we have %d\n",
+                verbose, VSCARD_VERSION);
+        }
+    }
+    if (incoming->magic != VSCARD_MAGIC) {
+        printf("unexpected magic: got %d, expected %d\n",
+            incoming->magic, VSCARD_MAGIC);
+        return -1;
+    }
+    for (i = 0 ; i < num_capabilities; ++i) {
+        capabilities[i] = ntohl(capabilities[i]);
+    }
+    /* Future: check capabilities */
+    /* remove whatever reader might be left in qemu,
+     * in case of an unclean previous exit. */
+    send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0);
+    /* launch the event_thread. This will trigger reader adds for all the
+     * existing readers */
+    rv = pthread_create(&thread_id, NULL, event_thread, NULL);
+    if (rv < 0) {
+        perror("pthread_create");
+        return rv;
+    }
+    return 0;
+}
+
+int
+main(
+    int argc,
+    char *argv[]
+) {
+    char *qemu_host;
+    char *qemu_port;
+    VSCMsgHeader mhHeader;
+    VSCMsgError *error_msg;
+
+    int rv;
+    int dwSendLength;
+    int dwRecvLength;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t pbSendBuffer[APDUBufSize];
+     VReaderStatus reader_status;
+    VReader *reader = NULL;
+    VCardEmulOptions *command_line_options = NULL;
+
+    char *cert_names[MAX_CERTS];
+    char *emul_args = NULL;
+    int cert_count = 0;
+    int c;
+
+    while ((c = getopt(argc, argv, "c:e:pd:")) != -1) {
+        switch (c) {
+        case 'c':
+            if (cert_count >= MAX_CERTS) {
+                printf("too many certificates (max = %d)\n", MAX_CERTS);
+                exit(5);
+            }
+            cert_names[cert_count++] = optarg;
+            break;
+        case 'e':
+            emul_args = optarg;
+            break;
+        case 'p':
+            print_usage();
+            exit(4);
+            break;
+        case 'd':
+            verbose = get_id_from_string(optarg, 1);
+            break;
+        }
+    }
+
+    if (argc - optind != 2) {
+        print_usage();
+        exit(4);
+    }
+
+    if (cert_count > 0) {
+        char *new_args;
+        int len, i;
+        /* if we've given some -c options, we clearly we want do so some
+         * software emulation.  add that emulation now. this is NSS Emulator
+         * specific */
+        if (emul_args == NULL) {
+            emul_args = (char *)"db=\"/etc/pki/nssdb\"";
+        }
+#define SOFT_STRING ",soft=(,Virtual Reader,CAC,,"
+             /* 2 == close paren & null */
+        len = strlen(emul_args) + strlen(SOFT_STRING) + 2;
+        for (i = 0; i < cert_count; i++) {
+            len += strlen(cert_names[i])+1; /* 1 == comma */
+        }
+        new_args = qemu_malloc(len);
+        strcpy(new_args, emul_args);
+        strcat(new_args, SOFT_STRING);
+        for (i = 0; i < cert_count; i++) {
+            strcat(new_args, cert_names[i]);
+            strcat(new_args, ",");
+        }
+        strcat(new_args, ")");
+        emul_args = new_args;
+    }
+    if (emul_args) {
+        command_line_options = vcard_emul_options(emul_args);
+    }
+
+    qemu_host = strdup(argv[argc - 2]);
+    qemu_port = strdup(argv[argc - 1]);
+    sock = connect_to_qemu(qemu_host, qemu_port);
+
+    qemu_mutex_init(&write_lock);
+    qemu_mutex_init(&pending_reader_lock);
+    qemu_cond_init(&pending_reader_condition);
+
+    vcard_emul_init(command_line_options);
+
+    printf("> ");
+    fflush(stdout);
+
+    /* Send init message, Host responds (and then we send reader attachments) */
+    VSCMsgInit init = {
+        .version = htonl(VSCARD_VERSION),
+        .magic = VSCARD_MAGIC,
+        .capabilities = {0}
+    };
+    send_msg(VSC_Init, mhHeader.reader_id, &init, sizeof(init));
+
+    do {
+        fd_set fds;
+
+        FD_ZERO(&fds);
+        FD_SET(1, &fds);
+        FD_SET(sock, &fds);
+
+        /* waiting on input from the socket */
+        rv = select(sock+1, &fds, NULL, NULL, NULL);
+        if (rv < 0) {
+            /* handle error */
+            perror("select");
+            return 7;
+        }
+        if (FD_ISSET(1, &fds)) {
+            do_command();
+        }
+        if (!FD_ISSET(sock, &fds)) {
+            continue;
+        }
+
+        rv = read(sock, &mhHeader, sizeof(mhHeader));
+        if (rv < sizeof(mhHeader)) {
+            /* Error */
+            if (rv < 0) {
+                perror("header read error\n");
+            } else {
+                fprintf(stderr, "header short read %d\n", rv);
+            }
+            return 8;
+        }
+        mhHeader.type = ntohl(mhHeader.type);
+        mhHeader.reader_id = ntohl(mhHeader.reader_id);
+        mhHeader.length = ntohl(mhHeader.length);
+        if (verbose) {
+            printf("Header: type=%d, reader_id=%d length=%d (0x%x)\n",
+                    mhHeader.type, mhHeader.reader_id, mhHeader.length,
+                                               mhHeader.length);
+        }
+        switch (mhHeader.type) {
+        case VSC_APDU:
+        case VSC_Flush:
+        case VSC_Error:
+        case VSC_Init:
+            rv = read(sock, pbSendBuffer, mhHeader.length);
+            break;
+        default:
+            fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type);
+            return 0;
+        }
+        switch (mhHeader.type) {
+        case VSC_APDU:
+            if (rv < 0) {
+                /* Error */
+                fprintf(stderr, "read error\n");
+                close(sock);
+                return 8;
+            }
+            if (verbose) {
+                printf(" recv APDU: ");
+                print_byte_array(pbSendBuffer, mhHeader.length);
+            }
+            /* Transmit recieved APDU */
+            dwSendLength = mhHeader.length;
+            dwRecvLength = sizeof(pbRecvBuffer);
+            reader = vreader_get_reader_by_id(mhHeader.reader_id);
+            reader_status = vreader_xfr_bytes(reader,
+                pbSendBuffer, dwSendLength,
+                pbRecvBuffer, &dwRecvLength);
+            if (reader_status == VREADER_OK) {
+                mhHeader.length = dwRecvLength;
+                if (verbose) {
+                    printf(" send response: ");
+                    print_byte_array(pbRecvBuffer, mhHeader.length);
+                }
+                send_msg(VSC_APDU, mhHeader.reader_id,
+                         pbRecvBuffer, dwRecvLength);
+            } else {
+                rv = reader_status; /* warning: not meaningful */
+                send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t));
+            }
+            vreader_free(reader);
+            reader = NULL; /* we've freed it, don't use it by accident
+                              again */
+            break;
+        case VSC_Flush:
+            /* TODO: actually flush */
+            send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0);
+            break;
+        case VSC_Error:
+            error_msg = (VSCMsgError *) pbSendBuffer;
+            if (error_msg->code == VSC_SUCCESS) {
+                qemu_mutex_lock(&pending_reader_lock);
+                if (pending_reader) {
+                    vreader_set_id(pending_reader, mhHeader.reader_id);
+                    vreader_free(pending_reader);
+                    pending_reader = NULL;
+                    qemu_cond_signal(&pending_reader_condition);
+                }
+                qemu_mutex_unlock(&pending_reader_lock);
+                break;
+            }
+            printf("warning: qemu refused to add reader\n");
+            if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) {
+                /* clear pending reader, qemu can't handle any more */
+                qemu_mutex_lock(&pending_reader_lock);
+                if (pending_reader) {
+                    pending_reader = NULL;
+                    /* make sure the event loop doesn't hang */
+                    qemu_cond_signal(&pending_reader_condition);
+                }
+                qemu_mutex_unlock(&pending_reader_lock);
+            }
+            break;
+        case VSC_Init:
+            if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) {
+                return -1;
+            }
+            break;
+        default:
+            printf("Default\n");
+            return 0;
+        }
+    } while (rv >= 0);
+
+    return 0;
+}
index 71822233819b07cc2b99f8d57ae0583fa0b319d1..e3127df4ac834529f69371078e791951f9fbe179 100644 (file)
 #define TARGET_NR_timerfd                      477
 #define TARGET_NR_eventfd                      478
 
-/* The following aliases are defined in order to match up with the
-   standard i386 syscalls implemented in syscalls.c.  */
-#define TARGET_NR_chown32      TARGET_NR_chown
-#define TARGET_NR_setuid32     TARGET_NR_setuid
-#define TARGET_NR_setgid32     TARGET_NR_setgid
-#define TARGET_NR_setfsuid32   TARGET_NR_setfsuid
-#define TARGET_NR_setfsgid32   TARGET_NR_setfsgid
index 0a87c4313328f43f86f37c0d3cb3da2e18e77ac2..eebd93fc00f5297c43691ab095b8e95cb4b2564a 100644 (file)
@@ -144,7 +144,7 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs)
 
 #if 0
   fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n",
-          opcode, qregs[REG_PC]);
+          opcode, qregs[ARM_REG_PC]);
 #endif
   fpa11 = GET_FPA11();
 
index f17647bdb950451495f2eadd8d3a7afe12941d2b..002b3cbb8267eb20b1d895753d103688a1274e73 100644 (file)
@@ -111,7 +111,7 @@ static inline void writeConditionCodes(unsigned int x)
         cpsr_write(user_registers,x,CPSR_NZCV);
 }
 
-#define REG_PC 15
+#define ARM_REG_PC 15
 
 unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs);
 
index b12e27dcb07608c98b7c6991d49c173612af2d72..3e7a938253a06f277c3e69681a493d4a349b8e41 100644 (file)
@@ -220,7 +220,7 @@ static unsigned int PerformLDF(const unsigned int opcode)
    //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
 
    pBase = readRegister(getRn(opcode));
-   if (REG_PC == getRn(opcode))
+   if (ARM_REG_PC == getRn(opcode))
    {
      pBase += 8;
      write_back = 0;
@@ -256,7 +256,7 @@ static unsigned int PerformSTF(const unsigned int opcode)
    SetRoundingMode(ROUND_TO_NEAREST);
 
    pBase = readRegister(getRn(opcode));
-   if (REG_PC == getRn(opcode))
+   if (ARM_REG_PC == getRn(opcode))
    {
      pBase += 8;
      write_back = 0;
@@ -289,7 +289,7 @@ static unsigned int PerformLFM(const unsigned int opcode)
    target_ulong pBase, pAddress, pFinal;
 
    pBase = readRegister(getRn(opcode));
-   if (REG_PC == getRn(opcode))
+   if (ARM_REG_PC == getRn(opcode))
    {
      pBase += 8;
      write_back = 0;
@@ -322,7 +322,7 @@ static unsigned int PerformSFM(const unsigned int opcode)
    target_ulong pBase, pAddress, pFinal;
 
    pBase = readRegister(getRn(opcode));
-   if (REG_PC == getRn(opcode))
+   if (ARM_REG_PC == getRn(opcode))
    {
      pBase += 8;
      write_back = 0;
index be54e9515dd268f91ca3bf5136d0cc39f6f85f68..801189798bbab153636ba947b3d752a168271ec7 100644 (file)
@@ -159,7 +159,7 @@ PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
    }
 
    /* test for equal condition */
-   if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
+   if (floatx80_eq_quiet(Fn,Fm, &fpa11->fp_status))
    {
       flags |= CC_ZERO;
    }
index fe5410e6f919ca06d4877203801a62f57f8cdbed..4c399f8e337b307d514e94039f71ed58dd63d005 100644 (file)
@@ -339,6 +339,80 @@ enum
 
 #endif
 
+#ifdef TARGET_UNICORE32
+
+#define ELF_START_MMAP          0x80000000
+
+#define elf_check_arch(x)       ((x) == EM_UNICORE32)
+
+#define ELF_CLASS               ELFCLASS32
+#define ELF_DATA                ELFDATA2LSB
+#define ELF_ARCH                EM_UNICORE32
+
+static inline void init_thread(struct target_pt_regs *regs,
+        struct image_info *infop)
+{
+    abi_long stack = infop->start_stack;
+    memset(regs, 0, sizeof(*regs));
+    regs->UC32_REG_asr = 0x10;
+    regs->UC32_REG_pc = infop->entry & 0xfffffffe;
+    regs->UC32_REG_sp = infop->start_stack;
+    /* FIXME - what to for failure of get_user()? */
+    get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */
+    get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */
+    /* XXX: it seems that r0 is zeroed after ! */
+    regs->UC32_REG_00 = 0;
+}
+
+#define ELF_NREG    34
+typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
+
+static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
+{
+    (*regs)[0] = env->regs[0];
+    (*regs)[1] = env->regs[1];
+    (*regs)[2] = env->regs[2];
+    (*regs)[3] = env->regs[3];
+    (*regs)[4] = env->regs[4];
+    (*regs)[5] = env->regs[5];
+    (*regs)[6] = env->regs[6];
+    (*regs)[7] = env->regs[7];
+    (*regs)[8] = env->regs[8];
+    (*regs)[9] = env->regs[9];
+    (*regs)[10] = env->regs[10];
+    (*regs)[11] = env->regs[11];
+    (*regs)[12] = env->regs[12];
+    (*regs)[13] = env->regs[13];
+    (*regs)[14] = env->regs[14];
+    (*regs)[15] = env->regs[15];
+    (*regs)[16] = env->regs[16];
+    (*regs)[17] = env->regs[17];
+    (*regs)[18] = env->regs[18];
+    (*regs)[19] = env->regs[19];
+    (*regs)[20] = env->regs[20];
+    (*regs)[21] = env->regs[21];
+    (*regs)[22] = env->regs[22];
+    (*regs)[23] = env->regs[23];
+    (*regs)[24] = env->regs[24];
+    (*regs)[25] = env->regs[25];
+    (*regs)[26] = env->regs[26];
+    (*regs)[27] = env->regs[27];
+    (*regs)[28] = env->regs[28];
+    (*regs)[29] = env->regs[29];
+    (*regs)[30] = env->regs[30];
+    (*regs)[31] = env->regs[31];
+
+    (*regs)[32] = cpu_asr_read((CPUState *)env);
+    (*regs)[33] = env->regs[0]; /* XXX */
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE               4096
+
+#define ELF_HWCAP                       (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64)
+
+#endif
+
 #ifdef TARGET_SPARC
 #ifdef TARGET_SPARC64
 
index 526aaa2a7649fc2d163edd5fe0cee15bf0c1aafc..42b3ae37253663fc2dd7da43e20e8e05826dcf84 100644 (file)
   IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
   IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
   IOCTL(SIOCSIFLINK, 0, TYPE_NULL)
-  IOCTL(SIOCGIFCONF, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifconf)))
+  IOCTL_SPECIAL(SIOCGIFCONF, IOC_W | IOC_R, do_ioctl_ifconf,
+                MK_PTR(MK_STRUCT(STRUCT_ifconf)))
   IOCTL(SIOCGIFENCAP, IOC_RW, MK_PTR(TYPE_INT))
   IOCTL(SIOCSIFENCAP, IOC_W, MK_PTR(TYPE_INT))
   IOCTL(SIOCDARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
   IOCTL(SIOCDRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
   IOCTL(SIOCSRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
   IOCTL(SIOCGRARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
+  IOCTL(SIOCGIWNAME, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq)))
 
   IOCTL(CDROMPAUSE, 0, TYPE_NULL)
   IOCTL(CDROMSTART, 0, TYPE_NULL)
index e651bfdad812a0319245ca3a749ce21d0d15691a..a1e37e494878a1fcad7adbc5f7ece26fba6de0ec 100644 (file)
@@ -816,6 +816,83 @@ void cpu_loop(CPUARMState *env)
 
 #endif
 
+#ifdef TARGET_UNICORE32
+
+void cpu_loop(CPUState *env)
+{
+    int trapnr;
+    unsigned int n, insn;
+    target_siginfo_t info;
+
+    for (;;) {
+        cpu_exec_start(env);
+        trapnr = uc32_cpu_exec(env);
+        cpu_exec_end(env);
+        switch (trapnr) {
+        case UC32_EXCP_PRIV:
+            {
+                /* system call */
+                get_user_u32(insn, env->regs[31] - 4);
+                n = insn & 0xffffff;
+
+                if (n >= UC32_SYSCALL_BASE) {
+                    /* linux syscall */
+                    n -= UC32_SYSCALL_BASE;
+                    if (n == UC32_SYSCALL_NR_set_tls) {
+                            cpu_set_tls(env, env->regs[0]);
+                            env->regs[0] = 0;
+                    } else {
+                        env->regs[0] = do_syscall(env,
+                                                  n,
+                                                  env->regs[0],
+                                                  env->regs[1],
+                                                  env->regs[2],
+                                                  env->regs[3],
+                                                  env->regs[4],
+                                                  env->regs[5]);
+                    }
+                } else {
+                    goto error;
+                }
+            }
+            break;
+        case UC32_EXCP_TRAP:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            /* XXX: check env->error_code */
+            info.si_code = TARGET_SEGV_MAPERR;
+            info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
+            queue_signal(env, info.si_signo, &info);
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(env, info.si_signo, &info);
+                }
+            }
+            break;
+        default:
+            goto error;
+        }
+        process_pending_signals(env);
+    }
+
+error:
+    fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
+    cpu_dump_state(env, stderr, fprintf, 0);
+    abort();
+}
+#endif
+
 #ifdef TARGET_SPARC
 #define SPARC64_STACK_BIAS 2047
 
@@ -2258,7 +2335,7 @@ void cpu_loop (CPUState *env)
                     break;
                 default:
                     printf ("Unhandled hw-exception: 0x%x\n",
-                            env->sregs[SR_ESR] & 5);
+                            env->sregs[SR_ESR] & ESR_EC_MASK);
                     cpu_dump_state(env, stderr, fprintf, 0);
                     exit (1);
                     break;
@@ -2925,6 +3002,8 @@ int main(int argc, char **argv, char **envp)
 #endif
 #elif defined(TARGET_ARM)
         cpu_model = "any";
+#elif defined(TARGET_UNICORE32)
+        cpu_model = "any";
 #elif defined(TARGET_M68K)
         cpu_model = "any";
 #elif defined(TARGET_SPARC)
@@ -3227,6 +3306,14 @@ int main(int argc, char **argv, char **envp)
             env->regs[i] = regs->uregs[i];
         }
     }
+#elif defined(TARGET_UNICORE32)
+    {
+        int i;
+        cpu_asr_write(env, regs->uregs[32], 0xffffffff);
+        for (i = 0; i < 32; i++) {
+            env->regs[i] = regs->uregs[i];
+        }
+    }
 #elif defined(TARGET_SPARC)
     {
         int i;
@@ -3367,7 +3454,7 @@ int main(int argc, char **argv, char **envp)
 #error unsupported target CPU
 #endif
 
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
     ts->stack_base = info->start_stack;
     ts->heap_base = info->brk;
     /* This will be filled in on the first SYS_HEAPINFO call.  */
index 250814d9f7cbd938d1b4117a5dd97f68ae0c9c2a..f522f5e64a089c5d11c06dee550c25b8b80a58e1 100644 (file)
@@ -105,6 +105,9 @@ typedef struct TaskState {
     FPA11 fpa;
     int swi_errno;
 #endif
+#ifdef TARGET_UNICORE32
+    int swi_errno;
+#endif
 #if defined(TARGET_I386) && !defined(TARGET_X86_64)
     abi_ulong target_v86;
     struct vm86_saved_state vm86_saved_regs;
@@ -118,7 +121,7 @@ typedef struct TaskState {
 #ifdef TARGET_M68K
     int sim_syscalls;
 #endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
     /* Extra fields for semihosted binaries.  */
     uint32_t stack_base;
     uint32_t heap_base;
index 8dd398b9f23d4444cf2a484d20338fb8d0cb577a..fe9326aa7334d7e85f76ce08b5bdc686258bdac5 100644 (file)
@@ -9,6 +9,7 @@
 #include <sys/mount.h>
 #include <sys/mman.h>
 #include <unistd.h>
+#include <sched.h>
 #include "qemu.h"
 
 int do_strace=0;
@@ -63,6 +64,7 @@ UNUSED static void print_string(abi_long, int);
 UNUSED static void print_raw_param(const char *, abi_long, int);
 UNUSED static void print_timeval(abi_ulong, int);
 UNUSED static void print_number(abi_long, int);
+UNUSED static void print_signal(abi_ulong, int);
 
 /*
  * Utility functions
@@ -117,6 +119,37 @@ if( cmd == val ) { \
     gemu_log("%d",cmd);
 }
 
+static void
+print_signal(abi_ulong arg, int last)
+{
+    const char *signal_name = NULL;
+    switch(arg) {
+    case TARGET_SIGHUP: signal_name = "SIGHUP"; break;
+    case TARGET_SIGINT: signal_name = "SIGINT"; break;
+    case TARGET_SIGQUIT: signal_name = "SIGQUIT"; break;
+    case TARGET_SIGILL: signal_name = "SIGILL"; break;
+    case TARGET_SIGABRT: signal_name = "SIGABRT"; break;
+    case TARGET_SIGFPE: signal_name = "SIGFPE"; break;
+    case TARGET_SIGKILL: signal_name = "SIGKILL"; break;
+    case TARGET_SIGSEGV: signal_name = "SIGSEGV"; break;
+    case TARGET_SIGPIPE: signal_name = "SIGPIPE"; break;
+    case TARGET_SIGALRM: signal_name = "SIGALRM"; break;
+    case TARGET_SIGTERM: signal_name = "SIGTERM"; break;
+    case TARGET_SIGUSR1: signal_name = "SIGUSR1"; break;
+    case TARGET_SIGUSR2: signal_name = "SIGUSR2"; break;
+    case TARGET_SIGCHLD: signal_name = "SIGCHLD"; break;
+    case TARGET_SIGCONT: signal_name = "SIGCONT"; break;
+    case TARGET_SIGSTOP: signal_name = "SIGSTOP"; break;
+    case TARGET_SIGTTIN: signal_name = "SIGTTIN"; break;
+    case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break;
+    }
+    if (signal_name == NULL) {
+        print_raw_param("%ld", arg, 1);
+        return;
+    }
+    gemu_log("%s%s", signal_name, get_comma(last));
+}
+
 #ifdef TARGET_NR__newselect
 static void
 print_fdset(int n, abi_ulong target_fds_addr)
@@ -427,6 +460,44 @@ UNUSED static struct flags fcntl_flags[] = {
     FLAG_END,
 };
 
+UNUSED static struct flags clone_flags[] = {
+    FLAG_GENERIC(CLONE_VM),
+    FLAG_GENERIC(CLONE_FS),
+    FLAG_GENERIC(CLONE_FILES),
+    FLAG_GENERIC(CLONE_SIGHAND),
+    FLAG_GENERIC(CLONE_PTRACE),
+    FLAG_GENERIC(CLONE_VFORK),
+    FLAG_GENERIC(CLONE_PARENT),
+    FLAG_GENERIC(CLONE_THREAD),
+    FLAG_GENERIC(CLONE_NEWNS),
+    FLAG_GENERIC(CLONE_SYSVSEM),
+    FLAG_GENERIC(CLONE_SETTLS),
+    FLAG_GENERIC(CLONE_PARENT_SETTID),
+    FLAG_GENERIC(CLONE_CHILD_CLEARTID),
+    FLAG_GENERIC(CLONE_DETACHED),
+    FLAG_GENERIC(CLONE_UNTRACED),
+    FLAG_GENERIC(CLONE_CHILD_SETTID),
+#if defined(CLONE_NEWUTS)
+    FLAG_GENERIC(CLONE_NEWUTS),
+#endif
+#if defined(CLONE_NEWIPC)
+    FLAG_GENERIC(CLONE_NEWIPC),
+#endif
+#if defined(CLONE_NEWUSER)
+    FLAG_GENERIC(CLONE_NEWUSER),
+#endif
+#if defined(CLONE_NEWPID)
+    FLAG_GENERIC(CLONE_NEWPID),
+#endif
+#if defined(CLONE_NEWNET)
+    FLAG_GENERIC(CLONE_NEWNET),
+#endif
+#if defined(CLONE_IO)
+    FLAG_GENERIC(CLONE_IO),
+#endif
+    FLAG_END,
+};
+
 /*
  * print_xxx utility functions.  These are used to print syscall
  * parameters in certain format.  All of these have parameter
@@ -669,6 +740,39 @@ print_chmod(const struct syscallname *name,
 }
 #endif
 
+#ifdef TARGET_NR_clone
+static void
+print_clone(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+#if defined(TARGET_M68K)
+    print_flags(clone_flags, arg0, 0);
+    print_raw_param("newsp=0x" TARGET_ABI_FMT_lx, arg1, 1);
+#elif defined(TARGET_SH4) || defined(TARGET_ALPHA)
+    print_flags(clone_flags, arg0, 0);
+    print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg1, 0);
+    print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
+    print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg3, 0);
+    print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg4, 1);
+#elif defined(TARGET_CRIS)
+    print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg0, 0);
+    print_flags(clone_flags, arg1, 0);
+    print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
+    print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg3, 0);
+    print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg4, 1);
+#else
+    print_flags(clone_flags, arg0, 0);
+    print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg1, 0);
+    print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
+    print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg3, 0);
+    print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg4, 1);
+#endif
+    print_syscall_epilogue(name);
+}
+#endif
+
 #ifdef TARGET_NR_creat
 static void
 print_creat(const struct syscallname *name,
@@ -805,6 +909,28 @@ print_linkat(const struct syscallname *name,
 }
 #endif
 
+#ifdef TARGET_NR__llseek
+static void
+print__llseek(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    const char *whence = "UNKNOWN";
+    print_syscall_prologue(name);
+    print_raw_param("%d", arg0, 0);
+    print_raw_param("%ld", arg1, 0);
+    print_raw_param("%ld", arg2, 0);
+    print_pointer(arg3, 0);
+    switch(arg4) {
+    case SEEK_SET: whence = "SEEK_SET"; break;
+    case SEEK_CUR: whence = "SEEK_CUR"; break;
+    case SEEK_END: whence = "SEEK_END"; break;
+    }
+    gemu_log("%s",whence);
+    print_syscall_epilogue(name);
+}
+#endif
+
 #if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \
     defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64)
 static void
@@ -875,6 +1001,40 @@ print_rmdir(const struct syscallname *name,
 }
 #endif
 
+#ifdef TARGET_NR_rt_sigaction
+static void
+print_rt_sigaction(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_signal(arg0, 0);
+    print_pointer(arg1, 0);
+    print_pointer(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_rt_sigprocmask
+static void
+print_rt_sigprocmask(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    const char *how = "UNKNOWN";
+    print_syscall_prologue(name);
+    switch(arg0) {
+    case TARGET_SIG_BLOCK: how = "SIG_BLOCK"; break;
+    case TARGET_SIG_UNBLOCK: how = "SIG_UNBLOCK"; break;
+    case TARGET_SIG_SETMASK: how = "SIG_SETMASK"; break;
+    }
+    gemu_log("%s,",how);
+    print_pointer(arg1, 0);
+    print_pointer(arg2, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
 #ifdef TARGET_NR_mknod
 static void
 print_mknod(const struct syscallname *name,
@@ -1298,6 +1458,19 @@ print_futex(const struct syscallname *name,
 }
 #endif
 
+#ifdef TARGET_NR_kill
+static void
+print_kill(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_raw_param("%d", arg0, 0);
+    print_signal(arg1, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
 /*
  * An array of all of the syscalls we know about
  */
index 563a67f0a2e5b6f6b3f78b44264664b0532a8a2d..a7eeaef99fd5eb29dce6710ab807fca6389f911c 100644 (file)
@@ -85,7 +85,7 @@
 { TARGET_NR_clock_settime, "clock_settime" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_clone
-{ TARGET_NR_clone, "clone" , NULL, NULL, NULL },
+{ TARGET_NR_clone, "clone" , NULL, print_clone, NULL },
 #endif
 #ifdef TARGET_NR_close
 { TARGET_NR_close, "close" , "%s(%d)", NULL, NULL },
 { TARGET_NR_getpgrp, "getpgrp" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_getpid
-{ TARGET_NR_getpid, "getpid" , NULL, NULL, NULL },
+{ TARGET_NR_getpid, "getpid" , "%s()", NULL, NULL },
 #endif
 #ifdef TARGET_NR_getpmsg
 { TARGET_NR_getpmsg, "getpmsg" , NULL, NULL, NULL },
 { TARGET_NR_keyctl, "keyctl" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_kill
-{ TARGET_NR_kill, "kill" , NULL, NULL, NULL },
+{ TARGET_NR_kill, "kill", NULL, print_kill, NULL },
 #endif
 #ifdef TARGET_NR_lchown
 { TARGET_NR_lchown, "lchown" , NULL, NULL, NULL },
 { TARGET_NR_llistxattr, "llistxattr" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR__llseek
-{ TARGET_NR__llseek, "_llseek" , NULL, NULL, NULL },
+{ TARGET_NR__llseek, "_llseek" , NULL, print__llseek, NULL },
 #endif
 #ifdef TARGET_NR_lock
 { TARGET_NR_lock, "lock" , NULL, NULL, NULL },
 { TARGET_NR_rmdir, "rmdir" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_rt_sigaction
-{ TARGET_NR_rt_sigaction, "rt_sigaction" , NULL, NULL, NULL },
+{ TARGET_NR_rt_sigaction, "rt_sigaction" , NULL, print_rt_sigaction, NULL },
 #endif
 #ifdef TARGET_NR_rt_sigpending
 { TARGET_NR_rt_sigpending, "rt_sigpending" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_rt_sigprocmask
-{ TARGET_NR_rt_sigprocmask, "rt_sigprocmask" , NULL, NULL, NULL },
+{ TARGET_NR_rt_sigprocmask, "rt_sigprocmask" , NULL, print_rt_sigprocmask, NULL },
 #endif
 #ifdef TARGET_NR_rt_sigqueueinfo
 { TARGET_NR_rt_sigqueueinfo, "rt_sigqueueinfo" , NULL, NULL, NULL },
index bb0999d1abe73b337570478ae94dfc572bbe8511..279cef3cd486d50d9b56cdb49e4fda270cb3374c 100644 (file)
@@ -59,6 +59,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 //#include <sys/user.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
+#include <linux/wireless.h>
 #include <qemu-common.h>
 #ifdef TARGET_GPROF
 #include <sys/gmon.h>
@@ -196,7 +197,8 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,   \
 #define __NR_sys_inotify_add_watch __NR_inotify_add_watch
 #define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
 
-#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
+#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
+    defined(__s390x__)
 #define __NR__llseek __NR_lseek
 #endif
 
@@ -326,7 +328,7 @@ static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
   return (fchmodat(dirfd, pathname, mode, 0));
 }
 #endif
-#if defined(TARGET_NR_fchownat) && defined(USE_UID16)
+#if defined(TARGET_NR_fchownat)
 static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
     gid_t group, int flags)
 {
@@ -435,7 +437,7 @@ _syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
 #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
 _syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
 #endif
-#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
+#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
 _syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
           uid_t,owner,gid_t,group,int,flags)
 #endif
@@ -2970,7 +2972,6 @@ static abi_long do_ipc(unsigned int call, int first,
 #endif
 
 /* kernel structure types definitions */
-#define IFNAMSIZ        16
 
 #define STRUCT(name, ...) STRUCT_ ## name,
 #define STRUCT_SPECIAL(name) STRUCT_ ## name,
@@ -3095,6 +3096,100 @@ static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
 }
 #endif
 
+static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                int fd, abi_long cmd, abi_long arg)
+{
+    const argtype *arg_type = ie->arg_type;
+    int target_size;
+    void *argptr;
+    int ret;
+    struct ifconf *host_ifconf;
+    uint32_t outbufsz;
+    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
+    int target_ifreq_size;
+    int nb_ifreq;
+    int free_buf = 0;
+    int i;
+    int target_ifc_len;
+    abi_long target_ifc_buf;
+    int host_ifc_len;
+    char *host_ifc_buf;
+
+    assert(arg_type[0] == TYPE_PTR);
+    assert(ie->access == IOC_RW);
+
+    arg_type++;
+    target_size = thunk_type_size(arg_type, 0);
+
+    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+    if (!argptr)
+        return -TARGET_EFAULT;
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+
+    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
+    target_ifc_len = host_ifconf->ifc_len;
+    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
+
+    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
+    nb_ifreq = target_ifc_len / target_ifreq_size;
+    host_ifc_len = nb_ifreq * sizeof(struct ifreq);
+
+    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
+    if (outbufsz > MAX_STRUCT_SIZE) {
+        /* We can't fit all the extents into the fixed size buffer.
+         * Allocate one that is large enough and use it instead.
+         */
+        host_ifconf = malloc(outbufsz);
+        if (!host_ifconf) {
+            return -TARGET_ENOMEM;
+        }
+        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
+        free_buf = 1;
+    }
+    host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
+
+    host_ifconf->ifc_len = host_ifc_len;
+    host_ifconf->ifc_buf = host_ifc_buf;
+
+    ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
+    if (!is_error(ret)) {
+       /* convert host ifc_len to target ifc_len */
+
+        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
+        target_ifc_len = nb_ifreq * target_ifreq_size;
+        host_ifconf->ifc_len = target_ifc_len;
+
+       /* restore target ifc_buf */
+
+        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
+
+       /* copy struct ifconf to target user */
+
+        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+        if (!argptr)
+            return -TARGET_EFAULT;
+        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
+        unlock_user(argptr, arg, target_size);
+
+       /* copy ifreq[] to target user */
+
+        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
+        for (i = 0; i < nb_ifreq ; i++) {
+            thunk_convert(argptr + i * target_ifreq_size,
+                          host_ifc_buf + i * sizeof(struct ifreq),
+                          ifreq_arg_type, THUNK_TARGET);
+        }
+        unlock_user(argptr, target_ifc_buf, target_ifc_len);
+    }
+
+    if (free_buf) {
+        free(host_ifconf);
+    }
+
+    return ret;
+}
+
 static IOCTLEntry ioctl_entries[] = {
 #define IOCTL(cmd, access, ...) \
     { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
@@ -3690,9 +3785,9 @@ static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
 
 #endif /* defined(TARGET_I386) */
 
-#if defined(CONFIG_USE_NPTL)
+#define NEW_STACK_SIZE 0x40000
 
-#define NEW_STACK_SIZE PTHREAD_STACK_MIN
+#if defined(CONFIG_USE_NPTL)
 
 static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
 typedef struct {
@@ -3736,9 +3831,6 @@ static void *clone_func(void *arg)
     return NULL;
 }
 #else
-/* this stack is the equivalent of the kernel stack associated with a
-   thread/process */
-#define NEW_STACK_SIZE 8192
 
 static int clone_func(void *arg)
 {
@@ -4072,7 +4164,31 @@ static inline int low2highgid(int gid)
     else
         return gid;
 }
-
+static inline int tswapid(int id)
+{
+    return tswap16(id);
+}
+#else /* !USE_UID16 */
+static inline int high2lowuid(int uid)
+{
+    return uid;
+}
+static inline int high2lowgid(int gid)
+{
+    return gid;
+}
+static inline int low2highuid(int uid)
+{
+    return uid;
+}
+static inline int low2highgid(int gid)
+{
+    return gid;
+}
+static inline int tswapid(int id)
+{
+    return tswap32(id);
+}
 #endif /* USE_UID16 */
 
 void syscall_init(void)
@@ -6384,20 +6500,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
 
             if (!is_error(ret)) {
-                if (arg2 > ret) {
-                    /* Zero out any extra space kernel didn't fill */
-                    unsigned long zero = arg2 - ret;
-                    p = alloca(zero);
-                    memset(p, 0, zero);
-                    if (copy_to_user(arg3 + zero, p, zero)) {
-                        goto efault;
-                    }
-                    arg2 = ret;
-                }
-                if (copy_to_user(arg3, mask, arg2)) {
+                if (copy_to_user(arg3, mask, ret)) {
                     goto efault;
                 }
-                ret = arg2;
             }
         }
         break;
@@ -6673,25 +6778,32 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             ret = host_to_target_stat64(cpu_env, arg3, &st);
         break;
 #endif
-#ifdef USE_UID16
     case TARGET_NR_lchown:
         if (!(p = lock_user_string(arg1)))
             goto efault;
         ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
         unlock_user(p, arg1, 0);
         break;
+#ifdef TARGET_NR_getuid
     case TARGET_NR_getuid:
         ret = get_errno(high2lowuid(getuid()));
         break;
+#endif
+#ifdef TARGET_NR_getgid
     case TARGET_NR_getgid:
         ret = get_errno(high2lowgid(getgid()));
         break;
+#endif
+#ifdef TARGET_NR_geteuid
     case TARGET_NR_geteuid:
         ret = get_errno(high2lowuid(geteuid()));
         break;
+#endif
+#ifdef TARGET_NR_getegid
     case TARGET_NR_getegid:
         ret = get_errno(high2lowgid(getegid()));
         break;
+#endif
     case TARGET_NR_setreuid:
         ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
         break;
@@ -6701,7 +6813,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_getgroups:
         {
             int gidsetsize = arg1;
-            uint16_t *target_grouplist;
+            target_id *target_grouplist;
             gid_t *grouplist;
             int i;
 
@@ -6714,7 +6826,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 if (!target_grouplist)
                     goto efault;
                 for(i = 0;i < ret; i++)
-                    target_grouplist[i] = tswap16(grouplist[i]);
+                    target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
                 unlock_user(target_grouplist, arg2, gidsetsize * 2);
             }
         }
@@ -6722,7 +6834,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_setgroups:
         {
             int gidsetsize = arg1;
-            uint16_t *target_grouplist;
+            target_id *target_grouplist;
             gid_t *grouplist;
             int i;
 
@@ -6733,7 +6845,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 goto fail;
             }
             for(i = 0;i < gidsetsize; i++)
-                grouplist[i] = tswap16(target_grouplist[i]);
+                grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
             unlock_user(target_grouplist, arg2, 0);
             ret = get_errno(setgroups(gidsetsize, grouplist));
         }
@@ -6809,7 +6921,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_setfsgid:
         ret = get_errno(setfsgid(arg1));
         break;
-#endif /* USE_UID16 */
 
 #ifdef TARGET_NR_lchown32
     case TARGET_NR_lchown32:
index 702652cb9e6094dad53b5455f47a8d72f99e024d..e05ddf9120f891f078f88ff964dead706335fd50 100644 (file)
 #define TARGET_IOC_TYPEBITS    8
 
 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
-    || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) || defined(TARGET_PPC) || defined(TARGET_MIPS)
+    || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
     /* 16 bit uid wrappers emulation */
 #define USE_UID16
+#define target_id uint16_t
+#else
+#define target_id uint32_t
 #endif
 
 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \
-    || defined(TARGET_M68K) || defined(TARGET_CRIS)
+    || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_UNICORE32)
 
 #define TARGET_IOC_SIZEBITS    14
 #define TARGET_IOC_DIRBITS     2
@@ -315,7 +318,10 @@ struct target_sigaction;
 int do_sigaction(int sig, const struct target_sigaction *act,
                  struct target_sigaction *oact);
 
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
+    || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined(TARGET_SH4) \
+    || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) \
+    || defined(TARGET_MICROBLAZE) || defined(TARGET_UNICORE32)
 
 #if defined(TARGET_SPARC)
 #define TARGET_SA_NOCLDSTOP    8u
@@ -762,6 +768,9 @@ struct target_pollfd {
 #define TARGET_SIOCADDDLCI     0x8980          /* Create new DLCI device       */
 #define TARGET_SIOCDELDLCI     0x8981          /* Delete DLCI device           */
 
+/* From <linux/wireless.h> */
+
+#define TARGET_SIOCGIWNAME     0x8B01          /* get name == wireless protocol */
 
 /* From <linux/fs.h> */
 
@@ -1002,7 +1011,8 @@ struct target_winsize {
 #define TARGET_MAP_UNINITIALIZED 0x4000000     /* for anonymous mmap, memory could be uninitialized */
 #endif
 
-#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_CRIS)
+#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) \
+    || defined(TARGET_CRIS) || defined(TARGET_UNICORE32)
 struct target_stat {
        unsigned short st_dev;
        unsigned short __pad1;
diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h
new file mode 100644 (file)
index 0000000..010cdd8
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#ifndef __UC32_SYSCALL_H__
+#define __UC32_SYSCALL_H__
+struct target_pt_regs {
+    abi_ulong uregs[34];
+};
+
+#define UC32_REG_pc             uregs[31]
+#define UC32_REG_lr             uregs[30]
+#define UC32_REG_sp             uregs[29]
+#define UC32_REG_ip             uregs[28]
+#define UC32_REG_fp             uregs[27]
+#define UC32_REG_26             uregs[26]
+#define UC32_REG_25             uregs[25]
+#define UC32_REG_24             uregs[24]
+#define UC32_REG_23             uregs[23]
+#define UC32_REG_22             uregs[22]
+#define UC32_REG_21             uregs[21]
+#define UC32_REG_20             uregs[20]
+#define UC32_REG_19             uregs[19]
+#define UC32_REG_18             uregs[18]
+#define UC32_REG_17             uregs[17]
+#define UC32_REG_16             uregs[16]
+#define UC32_REG_15             uregs[15]
+#define UC32_REG_14             uregs[14]
+#define UC32_REG_13             uregs[13]
+#define UC32_REG_12             uregs[12]
+#define UC32_REG_11             uregs[11]
+#define UC32_REG_10             uregs[10]
+#define UC32_REG_09             uregs[9]
+#define UC32_REG_08             uregs[8]
+#define UC32_REG_07             uregs[7]
+#define UC32_REG_06             uregs[6]
+#define UC32_REG_05             uregs[5]
+#define UC32_REG_04             uregs[4]
+#define UC32_REG_03             uregs[3]
+#define UC32_REG_02             uregs[2]
+#define UC32_REG_01             uregs[1]
+#define UC32_REG_00             uregs[0]
+#define UC32_REG_asr            uregs[32]
+#define UC32_REG_ORIG_00        uregs[33]
+
+#define UC32_SYSCALL_BASE               0x900000
+#define UC32_SYSCALL_ARCH_BASE          0xf0000
+#define UC32_SYSCALL_NR_set_tls         (UC32_SYSCALL_ARCH_BASE + 5)
+
+#define UNAME_MACHINE "UniCore-II"
+
+#endif /* __UC32_SYSCALL_H__ */
diff --git a/linux-user/unicore32/syscall_nr.h b/linux-user/unicore32/syscall_nr.h
new file mode 100644 (file)
index 0000000..9c72d84
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * This file contains the system call numbers for UniCore32 oldabi.
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#define TARGET_NR_restart_syscall               0
+#define TARGET_NR_exit                          1
+#define TARGET_NR_fork                          2
+#define TARGET_NR_read                          3
+#define TARGET_NR_write                         4
+#define TARGET_NR_open                          5
+#define TARGET_NR_close                         6
+#define TARGET_NR_waitpid                       7
+#define TARGET_NR_creat                         8
+#define TARGET_NR_link                          9
+#define TARGET_NR_unlink                        10
+#define TARGET_NR_execve                        11
+#define TARGET_NR_chdir                         12
+#define TARGET_NR_time                          13
+#define TARGET_NR_mknod                         14
+#define TARGET_NR_chmod                         15
+#define TARGET_NR_lchown                        16
+#define TARGET_NR_break                         17
+                                                /* 18 */
+#define TARGET_NR_lseek                         19
+#define TARGET_NR_getpid                        20
+#define TARGET_NR_mount                         21
+#define TARGET_NR_umount                        22
+#define TARGET_NR_setuid                        23
+#define TARGET_NR_getuid                        24
+#define TARGET_NR_stime                         25
+#define TARGET_NR_ptrace                        26
+#define TARGET_NR_alarm                         27
+                                                /* 28 */
+#define TARGET_NR_pause                         29
+#define TARGET_NR_utime                         30
+#define TARGET_NR_stty                          31
+#define TARGET_NR_gtty                          32
+#define TARGET_NR_access                        33
+#define TARGET_NR_nice                          34
+#define TARGET_NR_ftime                         35
+#define TARGET_NR_sync                          36
+#define TARGET_NR_kill                          37
+#define TARGET_NR_rename                        38
+#define TARGET_NR_mkdir                         39
+#define TARGET_NR_rmdir                         40
+#define TARGET_NR_dup                           41
+#define TARGET_NR_pipe                          42
+#define TARGET_NR_times                         43
+#define TARGET_NR_prof                          44
+#define TARGET_NR_brk                           45
+#define TARGET_NR_setgid                        46
+#define TARGET_NR_getgid                        47
+#define TARGET_NR_signal                        48
+#define TARGET_NR_geteuid                       49
+#define TARGET_NR_getegid                       50
+#define TARGET_NR_acct                          51
+#define TARGET_NR_umount2                       52
+#define TARGET_NR_lock                          53
+#define TARGET_NR_ioctl                         54
+#define TARGET_NR_fcntl                         55
+#define TARGET_NR_mpx                           56
+#define TARGET_NR_setpgid                       57
+#define TARGET_NR_ulimit                        58
+                                                /* 59 */
+#define TARGET_NR_umask                         60
+#define TARGET_NR_chroot                        61
+#define TARGET_NR_ustat                         62
+#define TARGET_NR_dup2                          63
+#define TARGET_NR_getppid                       64
+#define TARGET_NR_getpgrp                       65
+#define TARGET_NR_setsid                        66
+#define TARGET_NR_sigaction                     67
+#define TARGET_NR_sgetmask                      68
+#define TARGET_NR_ssetmask                      69
+#define TARGET_NR_setreuid                      70
+#define TARGET_NR_setregid                      71
+#define TARGET_NR_sigsuspend                    72
+#define TARGET_NR_sigpending                    73
+#define TARGET_NR_sethostname                   74
+#define TARGET_NR_setrlimit                     75
+#define TARGET_NR_getrlimit                     76
+#define TARGET_NR_getrusage                     77
+#define TARGET_NR_gettimeofday                  78
+#define TARGET_NR_settimeofday                  79
+#define TARGET_NR_getgroups                     80
+#define TARGET_NR_setgroups                     81
+#define TARGET_NR_select                        82
+#define TARGET_NR_symlink                       83
+                                                /* 84 */
+#define TARGET_NR_readlink                      85
+#define TARGET_NR_uselib                        86
+#define TARGET_NR_swapon                        87
+#define TARGET_NR_reboot                        88
+#define TARGET_NR_readdir                       89
+#define TARGET_NR_mmap                          90
+#define TARGET_NR_munmap                        91
+#define TARGET_NR_truncate                      92
+#define TARGET_NR_ftruncate                     93
+#define TARGET_NR_fchmod                        94
+#define TARGET_NR_fchown                        95
+#define TARGET_NR_getpriority                   96
+#define TARGET_NR_setpriority                   97
+#define TARGET_NR_profil                        98
+#define TARGET_NR_statfs                        99
+#define TARGET_NR_fstatfs                       100
+#define TARGET_NR_ioperm                        101
+#define TARGET_NR_socketcall                    102
+#define TARGET_NR_syslog                        103
+#define TARGET_NR_setitimer                     104
+#define TARGET_NR_getitimer                     105
+#define TARGET_NR_stat                          106
+#define TARGET_NR_lstat                         107
+#define TARGET_NR_fstat                         108
+                                                /* 109 */
+                                                /* 110 */
+#define TARGET_NR_vhangup                       111
+#define TARGET_NR_idle                          112
+#define TARGET_NR_syscall                       113
+#define TARGET_NR_wait4                         114
+#define TARGET_NR_swapoff                       115
+#define TARGET_NR_sysinfo                       116
+#define TARGET_NR_ipc                           117
+#define TARGET_NR_fsync                         118
+#define TARGET_NR_sigreturn                     119
+#define TARGET_NR_clone                         120
+#define TARGET_NR_setdomainname                 121
+#define TARGET_NR_uname                         122
+#define TARGET_NR_modify_ldt                    123
+#define TARGET_NR_adjtimex                      124
+#define TARGET_NR_mprotect                      125
+#define TARGET_NR_sigprocmask                   126
+#define TARGET_NR_create_module                 127
+#define TARGET_NR_init_module                   128
+#define TARGET_NR_delete_module                 129
+#define TARGET_NR_get_kernel_syms               130
+#define TARGET_NR_quotactl                      131
+#define TARGET_NR_getpgid                       132
+#define TARGET_NR_fchdir                        133
+#define TARGET_NR_bdflush                       134
+#define TARGET_NR_sysfs                         135
+#define TARGET_NR_personality                   136
+#define TARGET_NR_afs_syscall                   137
+#define TARGET_NR_setfsuid                      138
+#define TARGET_NR_setfsgid                      139
+#define TARGET_NR__llseek                       140
+#define TARGET_NR_getdents                      141
+#define TARGET_NR__newselect                    142
+#define TARGET_NR_flock                         143
+#define TARGET_NR_msync                         144
+#define TARGET_NR_readv                         145
+#define TARGET_NR_writev                        146
+#define TARGET_NR_getsid                        147
+#define TARGET_NR_fdatasync                     148
+#define TARGET_NR__sysctl                       149
+#define TARGET_NR_mlock                         150
+#define TARGET_NR_munlock                       151
+#define TARGET_NR_mlockall                      152
+#define TARGET_NR_munlockall                    153
+#define TARGET_NR_sched_setparam                154
+#define TARGET_NR_sched_getparam                155
+#define TARGET_NR_sched_setscheduler            156
+#define TARGET_NR_sched_getscheduler            157
+#define TARGET_NR_sched_yield                   158
+#define TARGET_NR_sched_get_priority_max        159
+#define TARGET_NR_sched_get_priority_min        160
+#define TARGET_NR_sched_rr_get_interval         161
+#define TARGET_NR_nanosleep                     162
+#define TARGET_NR_mremap                        163
+#define TARGET_NR_setresuid                     164
+#define TARGET_NR_getresuid                     165
+#define TARGET_NR_vm86                          166
+#define TARGET_NR_query_module                  167
+#define TARGET_NR_poll                          168
+#define TARGET_NR_nfsservctl                    169
+#define TARGET_NR_setresgid                     170
+#define TARGET_NR_getresgid                     171
+#define TARGET_NR_prctl                         172
+#define TARGET_NR_rt_sigreturn                  173
+#define TARGET_NR_rt_sigaction                  174
+#define TARGET_NR_rt_sigprocmask                175
+#define TARGET_NR_rt_sigpending                 176
+#define TARGET_NR_rt_sigtimedwait               177
+#define TARGET_NR_rt_sigqueueinfo               178
+#define TARGET_NR_rt_sigsuspend                 179
+#define TARGET_NR_pread                         180
+#define TARGET_NR_pwrite                        181
+#define TARGET_NR_chown                         182
+#define TARGET_NR_getcwd                        183
+#define TARGET_NR_capget                        184
+#define TARGET_NR_capset                        185
+#define TARGET_NR_sigaltstack                   186
+#define TARGET_NR_sendfile                      187
+                                                /* 188 */
+                                                /* 189 */
+#define TARGET_NR_vfork                         190
+#define TARGET_NR_ugetrlimit                    191
+#define TARGET_NR_mmap2                         192
+#define TARGET_NR_truncate64                    193
+#define TARGET_NR_ftruncate64                   194
+#define TARGET_NR_stat64                        195
+#define TARGET_NR_lstat64                       196
+#define TARGET_NR_fstat64                       197
+#define TARGET_NR_lchown32                      198
+#define TARGET_NR_getuid32                      199
+#define TARGET_NR_getgid32                      200
+#define TARGET_NR_geteuid32                     201
+#define TARGET_NR_getegid32                     202
+#define TARGET_NR_setreuid32                    203
+#define TARGET_NR_setregid32                    204
+#define TARGET_NR_getgroups32                   205
+#define TARGET_NR_setgroups32                   206
+#define TARGET_NR_fchown32                      207
+#define TARGET_NR_setresuid32                   208
+#define TARGET_NR_getresuid32                   209
+#define TARGET_NR_setresgid32                   210
+#define TARGET_NR_getresgid32                   211
+#define TARGET_NR_chown32                       212
+#define TARGET_NR_setuid32                      213
+#define TARGET_NR_setgid32                      214
+#define TARGET_NR_setfsuid32                    215
+#define TARGET_NR_setfsgid32                    216
+#define TARGET_NR_getdents64                    217
+#define TARGET_NR_pivot_root                    218
+#define TARGET_NR_mincore                       219
+#define TARGET_NR_madvise                       220
+#define TARGET_NR_fcntl64                       221
+                                                /* 222 */
+                                                /* 223 */
+#define TARGET_NR_gettid                        224
+#define TARGET_NR_readahead                     225
+#define TARGET_NR_setxattr                      226
+#define TARGET_NR_lsetxattr                     227
+#define TARGET_NR_fsetxattr                     228
+#define TARGET_NR_getxattr                      229
+#define TARGET_NR_lgetxattr                     230
+#define TARGET_NR_fgetxattr                     231
+#define TARGET_NR_listxattr                     232
+#define TARGET_NR_llistxattr                    233
+#define TARGET_NR_flistxattr                    234
+#define TARGET_NR_removexattr                   235
+#define TARGET_NR_lremovexattr                  236
+#define TARGET_NR_fremovexattr                  237
+#define TARGET_NR_tkill                         238
+#define TARGET_NR_sendfile64                    239
+#define TARGET_NR_futex                         240
+#define TARGET_NR_sched_setaffinity             241
+#define TARGET_NR_sched_getaffinity             242
+#define TARGET_NR_io_setup                      243
+#define TARGET_NR_io_destroy                    244
+#define TARGET_NR_io_getevents                  245
+#define TARGET_NR_io_submit                     246
+#define TARGET_NR_io_cancel                     247
+#define TARGET_NR_exit_group                    248
+#define TARGET_NR_lookup_dcookie                249
+#define TARGET_NR_epoll_create                  250
+#define TARGET_NR_epoll_ctl                     251
+#define TARGET_NR_epoll_wait                    252
+#define TARGET_NR_remap_file_pages              253
+                                                /* 254 */
+                                                /* 255 */
+                                                /* 256 */
+#define TARGET_NR_set_tid_address               256
+#define TARGET_NR_timer_create                  257
+#define TARGET_NR_timer_settime                 258
+#define TARGET_NR_timer_gettime                 259
+#define TARGET_NR_timer_getoverrun              260
+#define TARGET_NR_timer_delete                  261
+#define TARGET_NR_clock_settime                 262
+#define TARGET_NR_clock_gettime                 263
+#define TARGET_NR_clock_getres                  264
+#define TARGET_NR_clock_nanosleep               265
+#define TARGET_NR_statfs64                      266
+#define TARGET_NR_fstatfs64                     267
+#define TARGET_NR_tgkill                        268
+#define TARGET_NR_utimes                        269
+#define TARGET_NR_fadvise64_64                  270
+#define TARGET_NR_pciconfig_iobase              271
+#define TARGET_NR_pciconfig_read                272
+#define TARGET_NR_pciconfig_write               273
+#define TARGET_NR_mq_open                       274
+#define TARGET_NR_mq_unlink                     275
+#define TARGET_NR_mq_timedsend                  276
+#define TARGET_NR_mq_timedreceive               277
+#define TARGET_NR_mq_notify                     278
+#define TARGET_NR_mq_getsetattr                 279
+#define TARGET_NR_waitid                        280
+#define TARGET_NR_socket                        281
+#define TARGET_NR_bind                          282
+#define TARGET_NR_connect                       283
+#define TARGET_NR_listen                        284
+#define TARGET_NR_accept                        285
+#define TARGET_NR_getsockname                   286
+#define TARGET_NR_getpeername                   287
+#define TARGET_NR_socketpair                    288
+#define TARGET_NR_send                          289
+#define TARGET_NR_sendto                        290
+#define TARGET_NR_recv                          291
+#define TARGET_NR_recvfrom                      292
+#define TARGET_NR_shutdown                      293
+#define TARGET_NR_setsockopt                    294
+#define TARGET_NR_getsockopt                    295
+#define TARGET_NR_sendmsg                       296
+#define TARGET_NR_recvmsg                       297
+#define TARGET_NR_semop                         298
+#define TARGET_NR_semget                        299
+#define TARGET_NR_semctl                        300
+#define TARGET_NR_msgsnd                        301
+#define TARGET_NR_msgrcv                        302
+#define TARGET_NR_msgget                        303
+#define TARGET_NR_msgctl                        304
+#define TARGET_NR_shmat                         305
+#define TARGET_NR_shmdt                         306
+#define TARGET_NR_shmget                        307
+#define TARGET_NR_shmctl                        308
+#define TARGET_NR_add_key                       309
+#define TARGET_NR_request_key                   310
+#define TARGET_NR_keyctl                        311
+#define TARGET_NR_semtimedop                    312
+#define TARGET_NR_vserver                       313
+#define TARGET_NR_ioprio_set                    314
+#define TARGET_NR_ioprio_get                    315
+#define TARGET_NR_inotify_init                  316
+#define TARGET_NR_inotify_add_watch             317
+#define TARGET_NR_inotify_rm_watch              318
+#define TARGET_NR_mbind                         319
+#define TARGET_NR_get_mempolicy                 320
+#define TARGET_NR_set_mempolicy                 321
+#define TARGET_NR_openat                        322
+#define TARGET_NR_mkdirat                       323
+#define TARGET_NR_mknodat                       324
+#define TARGET_NR_fchownat                      325
+#define TARGET_NR_futimesat                     326
+#define TARGET_NR_fstatat64                     327
+#define TARGET_NR_unlinkat                      328
+#define TARGET_NR_renameat                      329
+#define TARGET_NR_linkat                        330
+#define TARGET_NR_symlinkat                     331
+#define TARGET_NR_readlinkat                    332
+#define TARGET_NR_fchmodat                      333
+#define TARGET_NR_faccessat                     334
+                                                /* 335 */
+                                                /* 336 */
+#define TARGET_NR_unshare                       337
+#define TARGET_NR_set_robust_list               338
+#define TARGET_NR_get_robust_list               339
+#define TARGET_NR_splice                        340
+#define TARGET_NR_sync_file_range2              341
+#define TARGET_NR_tee                           342
+#define TARGET_NR_vmsplice                      343
+#define TARGET_NR_move_pages                    344
+#define TARGET_NR_getcpu                        345
+                                                /* 346 */
+#define TARGET_NR_kexec_load                    347
+#define TARGET_NR_utimensat                     348
+#define TARGET_NR_signalfd                      349
+#define TARGET_NR_timerfd                       350
+#define TARGET_NR_eventfd                       351
+#define TARGET_NR_fallocate                     352
+#define TARGET_NR_timerfd_settime               353
+#define TARGET_NR_timerfd_gettime               354
+#define TARGET_NR_signalfd4                     355
+#define TARGET_NR_eventfd2                      356
+#define TARGET_NR_epoll_create1                 357
+#define TARGET_NR_dup3                          358
+#define TARGET_NR_pipe2                         359
+#define TARGET_NR_inotify_init1                 360
diff --git a/linux-user/unicore32/target_signal.h b/linux-user/unicore32/target_signal.h
new file mode 100644 (file)
index 0000000..8b255c4
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+/* this struct defines a stack used during syscall handling */
+typedef struct target_sigaltstack {
+    abi_ulong ss_sp;
+    abi_ulong ss_flags;
+    abi_ulong ss_size;
+} target_stack_t;
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK               1
+#define TARGET_SS_DISABLE               2
+
+#define get_sp_from_cpustate(cpustate)  (cpustate->regs[29])
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/unicore32/termbits.h b/linux-user/unicore32/termbits.h
new file mode 100644 (file)
index 0000000..a5fcd64
--- /dev/null
@@ -0,0 +1,2 @@
+/* NOTE: exactly the same as i386 */
+#include "../i386/termbits.h"
index 14718dd1d1fdbcd5e2f814ba10b658301cb57591..4b7aad8b6b599477bf19aa38d06b78d96c2db659 100644 (file)
@@ -17,7 +17,6 @@
 #include "qemu_socket.h"
 #include "migration.h"
 #include "qemu-char.h"
-#include "sysemu.h"
 #include "buffered_file.h"
 #include "block.h"
 #include <sys/types.h>
index 6d145056324bd7238ec6282c0632494f7cc6e54f..66d51c1cc0a242d8cef4010e9161a3e01b90b9ed 100644 (file)
@@ -16,7 +16,6 @@
 #include "migration.h"
 #include "monitor.h"
 #include "qemu-char.h"
-#include "sysemu.h"
 #include "buffered_file.h"
 #include "block.h"
 #include "qemu_socket.h"
index e8dff9d71a42be6c4dc75d13e043a2119cae0c02..d3d80c97022e2b23484987050afdbebde7a3e2af 100644 (file)
@@ -15,7 +15,6 @@
 #include "qemu_socket.h"
 #include "migration.h"
 #include "qemu-char.h"
-#include "sysemu.h"
 #include "buffered_file.h"
 #include "block.h"
 
index 8b967f2938fabd27222cd36e86582bace06d9b96..c8625c7f6501a0760cc9b7f32c947f7cb84f72be 100644 (file)
@@ -15,7 +15,6 @@
 #include "qemu_socket.h"
 #include "migration.h"
 #include "qemu-char.h"
-#include "sysemu.h"
 #include "buffered_file.h"
 #include "block.h"
 
index 21707922ef602a4348cee83e52b9389fd57ea444..050c56c5a4ef753c46c026963520191d7063cc18 100644 (file)
@@ -139,4 +139,13 @@ void add_migration_state_change_notifier(Notifier *notify);
 void remove_migration_state_change_notifier(Notifier *notify);
 int get_migration_state(void);
 
+uint64_t ram_bytes_remaining(void);
+uint64_t ram_bytes_transferred(void);
+uint64_t ram_bytes_total(void);
+
+int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque);
+int ram_load(QEMUFile *f, void *opaque, int version_id);
+
+extern int incoming_expected;
+
 #endif
index 76a82074ae7b45ff0b785bf68ff5a8cec67efbb8..5f3bc726bd60784fff1c0e517d2622265f13c5e0 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -1429,7 +1429,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
         if (l > line_size)
             l = line_size;
         if (is_physical) {
-            cpu_physical_memory_rw(addr, buf, l, 0);
+            cpu_physical_memory_read(addr, buf, l);
         } else {
             env = mon_get_cpu();
             if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) {
@@ -1605,7 +1605,7 @@ static int do_physical_memory_save(Monitor *mon, const QDict *qdict,
         l = sizeof(buf);
         if (l > size)
             l = size;
-        cpu_physical_memory_rw(addr, buf, l, 0);
+        cpu_physical_memory_read(addr, buf, l);
         if (fwrite(buf, 1, l, f) != l) {
             monitor_printf(mon, "fwrite() error in do_physical_memory_save\n");
             goto exit;
@@ -1625,17 +1625,16 @@ exit:
 static void do_sum(Monitor *mon, const QDict *qdict)
 {
     uint32_t addr;
-    uint8_t buf[1];
     uint16_t sum;
     uint32_t start = qdict_get_int(qdict, "start");
     uint32_t size = qdict_get_int(qdict, "size");
 
     sum = 0;
     for(addr = start; addr < (start + size); addr++) {
-        cpu_physical_memory_rw(addr, buf, 1, 0);
+        uint8_t val = ldub_phys(addr);
         /* BSD sum algorithm ('sum' Unix command) */
         sum = (sum >> 1) | (sum << 15);
-        sum += buf[0];
+        sum += val;
     }
     monitor_printf(mon, "%05d\n", sum);
 }
@@ -2026,7 +2025,7 @@ static void tlb_info_32(Monitor *mon, CPUState *env)
 
     pgd = env->cr[3] & ~0xfff;
     for(l1 = 0; l1 < 1024; l1++) {
-        cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4);
+        cpu_physical_memory_read(pgd + l1 * 4, &pde, 4);
         pde = le32_to_cpu(pde);
         if (pde & PG_PRESENT_MASK) {
             if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
@@ -2034,8 +2033,7 @@ static void tlb_info_32(Monitor *mon, CPUState *env)
                 print_pte(mon, (l1 << 22), pde, ~((1 << 21) - 1));
             } else {
                 for(l2 = 0; l2 < 1024; l2++) {
-                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
-                                             (uint8_t *)&pte, 4);
+                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4);
                     pte = le32_to_cpu(pte);
                     if (pte & PG_PRESENT_MASK) {
                         print_pte(mon, (l1 << 22) + (l2 << 12),
@@ -2056,13 +2054,12 @@ static void tlb_info_pae32(Monitor *mon, CPUState *env)
 
     pdp_addr = env->cr[3] & ~0x1f;
     for (l1 = 0; l1 < 4; l1++) {
-        cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8);
+        cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8);
         pdpe = le64_to_cpu(pdpe);
         if (pdpe & PG_PRESENT_MASK) {
             pd_addr = pdpe & 0x3fffffffff000ULL;
             for (l2 = 0; l2 < 512; l2++) {
-                cpu_physical_memory_read(pd_addr + l2 * 8,
-                                         (uint8_t *)&pde, 8);
+                cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8);
                 pde = le64_to_cpu(pde);
                 if (pde & PG_PRESENT_MASK) {
                     if (pde & PG_PSE_MASK) {
@@ -2072,8 +2069,7 @@ static void tlb_info_pae32(Monitor *mon, CPUState *env)
                     } else {
                         pt_addr = pde & 0x3fffffffff000ULL;
                         for (l3 = 0; l3 < 512; l3++) {
-                            cpu_physical_memory_read(pt_addr + l3 * 8,
-                                                     (uint8_t *)&pte, 8);
+                            cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8);
                             pte = le64_to_cpu(pte);
                             if (pte & PG_PRESENT_MASK) {
                                 print_pte(mon, (l1 << 30 ) + (l2 << 21)
@@ -2098,13 +2094,12 @@ static void tlb_info_64(Monitor *mon, CPUState *env)
 
     pml4_addr = env->cr[3] & 0x3fffffffff000ULL;
     for (l1 = 0; l1 < 512; l1++) {
-        cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8);
+        cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8);
         pml4e = le64_to_cpu(pml4e);
         if (pml4e & PG_PRESENT_MASK) {
             pdp_addr = pml4e & 0x3fffffffff000ULL;
             for (l2 = 0; l2 < 512; l2++) {
-                cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe,
-                                         8);
+                cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8);
                 pdpe = le64_to_cpu(pdpe);
                 if (pdpe & PG_PRESENT_MASK) {
                     if (pdpe & PG_PSE_MASK) {
@@ -2114,8 +2109,7 @@ static void tlb_info_64(Monitor *mon, CPUState *env)
                     } else {
                         pd_addr = pdpe & 0x3fffffffff000ULL;
                         for (l3 = 0; l3 < 512; l3++) {
-                            cpu_physical_memory_read(pd_addr + l3 * 8,
-                                                     (uint8_t *)&pde, 8);
+                            cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8);
                             pde = le64_to_cpu(pde);
                             if (pde & PG_PRESENT_MASK) {
                                 if (pde & PG_PSE_MASK) {
@@ -2128,8 +2122,7 @@ static void tlb_info_64(Monitor *mon, CPUState *env)
                                     for (l4 = 0; l4 < 512; l4++) {
                                         cpu_physical_memory_read(pt_addr
                                                                  + l4 * 8,
-                                                                 (uint8_t *)&pte,
-                                                                 8);
+                                                                 &pte, 8);
                                         pte = le64_to_cpu(pte);
                                         if (pte & PG_PRESENT_MASK) {
                                             print_pte(mon, (l1 << 39) +
@@ -2207,7 +2200,7 @@ static void mem_info_32(Monitor *mon, CPUState *env)
     last_prot = 0;
     start = -1;
     for(l1 = 0; l1 < 1024; l1++) {
-        cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4);
+        cpu_physical_memory_read(pgd + l1 * 4, &pde, 4);
         pde = le32_to_cpu(pde);
         end = l1 << 22;
         if (pde & PG_PRESENT_MASK) {
@@ -2216,8 +2209,7 @@ static void mem_info_32(Monitor *mon, CPUState *env)
                 mem_print(mon, &start, &last_prot, end, prot);
             } else {
                 for(l2 = 0; l2 < 1024; l2++) {
-                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
-                                             (uint8_t *)&pte, 4);
+                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4);
                     pte = le32_to_cpu(pte);
                     end = (l1 << 22) + (l2 << 12);
                     if (pte & PG_PRESENT_MASK) {
@@ -2246,14 +2238,13 @@ static void mem_info_pae32(Monitor *mon, CPUState *env)
     last_prot = 0;
     start = -1;
     for (l1 = 0; l1 < 4; l1++) {
-        cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8);
+        cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8);
         pdpe = le64_to_cpu(pdpe);
         end = l1 << 30;
         if (pdpe & PG_PRESENT_MASK) {
             pd_addr = pdpe & 0x3fffffffff000ULL;
             for (l2 = 0; l2 < 512; l2++) {
-                cpu_physical_memory_read(pd_addr + l2 * 8,
-                                         (uint8_t *)&pde, 8);
+                cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8);
                 pde = le64_to_cpu(pde);
                 end = (l1 << 30) + (l2 << 21);
                 if (pde & PG_PRESENT_MASK) {
@@ -2264,8 +2255,7 @@ static void mem_info_pae32(Monitor *mon, CPUState *env)
                     } else {
                         pt_addr = pde & 0x3fffffffff000ULL;
                         for (l3 = 0; l3 < 512; l3++) {
-                            cpu_physical_memory_read(pt_addr + l3 * 8,
-                                                     (uint8_t *)&pte, 8);
+                            cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8);
                             pte = le64_to_cpu(pte);
                             end = (l1 << 30) + (l2 << 21) + (l3 << 12);
                             if (pte & PG_PRESENT_MASK) {
@@ -2302,14 +2292,13 @@ static void mem_info_64(Monitor *mon, CPUState *env)
     last_prot = 0;
     start = -1;
     for (l1 = 0; l1 < 512; l1++) {
-        cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8);
+        cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8);
         pml4e = le64_to_cpu(pml4e);
         end = l1 << 39;
         if (pml4e & PG_PRESENT_MASK) {
             pdp_addr = pml4e & 0x3fffffffff000ULL;
             for (l2 = 0; l2 < 512; l2++) {
-                cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe,
-                                         8);
+                cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8);
                 pdpe = le64_to_cpu(pdpe);
                 end = (l1 << 39) + (l2 << 30);
                 if (pdpe & PG_PRESENT_MASK) {
@@ -2320,8 +2309,7 @@ static void mem_info_64(Monitor *mon, CPUState *env)
                     } else {
                         pd_addr = pdpe & 0x3fffffffff000ULL;
                         for (l3 = 0; l3 < 512; l3++) {
-                            cpu_physical_memory_read(pd_addr + l3 * 8,
-                                                     (uint8_t *)&pde, 8);
+                            cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8);
                             pde = le64_to_cpu(pde);
                             end = (l1 << 39) + (l2 << 30) + (l3 << 21);
                             if (pde & PG_PRESENT_MASK) {
@@ -2334,8 +2322,7 @@ static void mem_info_64(Monitor *mon, CPUState *env)
                                     for (l4 = 0; l4 < 512; l4++) {
                                         cpu_physical_memory_read(pt_addr
                                                                  + l4 * 8,
-                                                                 (uint8_t *)&pte,
-                                                                 8);
+                                                                 &pte, 8);
                                         pte = le64_to_cpu(pte);
                                         end = (l1 << 39) + (l2 << 30) +
                                             (l3 << 21) + (l4 << 12);
@@ -3462,7 +3449,7 @@ static const MonitorDef monitor_defs[] = {
     { "asr", offsetof(CPUState, asr) },
 #endif
     /* Segment registers */
-    { "sdr1", offsetof(CPUState, sdr1) },
+    { "sdr1", offsetof(CPUState, spr[SPR_SDR1]) },
     { "sr0", offsetof(CPUState, sr[0]) },
     { "sr1", offsetof(CPUState, sr[1]) },
     { "sr2", offsetof(CPUState, sr[2]) },
diff --git a/nbd.c b/nbd.c
index d8ebc4298fc0f5bd85b7ea1ff7eafd1cdb723af8..0dcd86b52fba3d963a67ef873243c8b3c78d21d0 100644 (file)
--- a/nbd.c
+++ b/nbd.c
@@ -49,7 +49,7 @@
 
 /* This is all part of the "official" NBD API */
 
-#define NBD_REPLY_SIZE         (4 + 4 + 8)
+#define NBD_REPLY_SIZE          (4 + 4 + 8)
 #define NBD_REQUEST_MAGIC       0x25609513
 #define NBD_REPLY_MAGIC         0x67446698
 
 #define NBD_DO_IT               _IO(0xab, 3)
 #define NBD_CLEAR_SOCK          _IO(0xab, 4)
 #define NBD_CLEAR_QUE           _IO(0xab, 5)
-#define NBD_PRINT_DEBUG                _IO(0xab, 6)
-#define NBD_SET_SIZE_BLOCKS    _IO(0xab, 7)
+#define NBD_PRINT_DEBUG         _IO(0xab, 6)
+#define NBD_SET_SIZE_BLOCKS     _IO(0xab, 7)
 #define NBD_DISCONNECT          _IO(0xab, 8)
 
-#define NBD_OPT_EXPORT_NAME    (1 << 0)
+#define NBD_OPT_EXPORT_NAME     (1 << 0)
 
 /* That's all folks */
 
@@ -107,155 +107,55 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
     return offset;
 }
 
-int tcp_socket_outgoing(const char *address, uint16_t port)
+static void combine_addr(char *buf, size_t len, const char* address,
+                         uint16_t port)
 {
-    int s;
-    struct in_addr in;
-    struct sockaddr_in addr;
-
-    s = socket(PF_INET, SOCK_STREAM, 0);
-    if (s == -1) {
-        return -1;
-    }
-
-    if (inet_aton(address, &in) == 0) {
-        struct hostent *ent;
-
-        ent = gethostbyname(address);
-        if (ent == NULL) {
-            goto error;
-        }
-
-        memcpy(&in, ent->h_addr, sizeof(in));
-    }
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
-
-    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-        goto error;
+    /* If the address-part contains a colon, it's an IPv6 IP so needs [] */
+    if (strstr(address, ":")) {
+        snprintf(buf, len, "[%s]:%u", address, port);
+    } else {
+        snprintf(buf, len, "%s:%u", address, port);
     }
-
-    return s;
-error:
-    closesocket(s);
-    return -1;
 }
 
-int tcp_socket_incoming(const char *address, uint16_t port)
+int tcp_socket_outgoing(const char *address, uint16_t port)
 {
-    int s;
-    struct in_addr in;
-    struct sockaddr_in addr;
-    int opt;
-
-    s = socket(PF_INET, SOCK_STREAM, 0);
-    if (s == -1) {
-        return -1;
-    }
-
-    if (inet_aton(address, &in) == 0) {
-        struct hostent *ent;
-
-        ent = gethostbyname(address);
-        if (ent == NULL) {
-            goto error;
-        }
-
-        memcpy(&in, ent->h_addr, sizeof(in));
-    }
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
-
-    opt = 1;
-    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-                   (const void *) &opt, sizeof(opt)) == -1) {
-        goto error;
-    }
-
-    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-        goto error;
-    }
-
-    if (listen(s, 128) == -1) {
-        goto error;
-    }
-
-    return s;
-error:
-    closesocket(s);
-    return -1;
+    char address_and_port[128];
+    combine_addr(address_and_port, 128, address, port);
+    return tcp_socket_outgoing_spec(address_and_port);
 }
 
-#ifndef _WIN32
-int unix_socket_incoming(const char *path)
+int tcp_socket_outgoing_spec(const char *address_and_port)
 {
-    int s;
-    struct sockaddr_un addr;
-
-    s = socket(PF_UNIX, SOCK_STREAM, 0);
-    if (s == -1) {
-        return -1;
-    }
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sun_family = AF_UNIX;
-    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
-
-    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-        goto error;
-    }
-
-    if (listen(s, 128) == -1) {
-        goto error;
-    }
-
-    return s;
-error:
-    closesocket(s);
-    return -1;
+    return inet_connect(address_and_port, SOCK_STREAM);
 }
 
-int unix_socket_outgoing(const char *path)
+int tcp_socket_incoming(const char *address, uint16_t port)
 {
-    int s;
-    struct sockaddr_un addr;
-
-    s = socket(PF_UNIX, SOCK_STREAM, 0);
-    if (s == -1) {
-        return -1;
-    }
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sun_family = AF_UNIX;
-    pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
-
-    if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-        goto error;
-    }
+    char address_and_port[128];
+    combine_addr(address_and_port, 128, address, port);
+    return tcp_socket_incoming_spec(address_and_port);
+}
 
-    return s;
-error:
-    closesocket(s);
-    return -1;
+int tcp_socket_incoming_spec(const char *address_and_port)
+{
+    char *ostr  = NULL;
+    int olen = 0;
+    return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0);
 }
-#else
+
 int unix_socket_incoming(const char *path)
 {
-    errno = ENOTSUP;
-    return -1;
+    char *ostr = NULL;
+    int olen = 0;
+
+    return unix_listen(path, ostr, olen);
 }
 
 int unix_socket_outgoing(const char *path)
 {
-    errno = ENOTSUP;
-    return -1;
+    return unix_connect(path);
 }
-#endif
-
 
 /* Basic flow
 
@@ -273,241 +173,241 @@ int unix_socket_outgoing(const char *path)
 
 int nbd_negotiate(int csock, off_t size)
 {
-       char buf[8 + 8 + 8 + 128];
-
-       /* Negotiate
-          [ 0 ..   7]   passwd   ("NBDMAGIC")
-          [ 8 ..  15]   magic    (0x00420281861253)
-          [16 ..  23]   size
-          [24 .. 151]   reserved (0)
-        */
-
-       TRACE("Beginning negotiation.");
-       memcpy(buf, "NBDMAGIC", 8);
-       cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
-       cpu_to_be64w((uint64_t*)(buf + 16), size);
-       memset(buf + 24, 0, 128);
-
-       if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
-               LOG("write failed");
-               errno = EINVAL;
-               return -1;
-       }
-
-       TRACE("Negotation succeeded.");
-
-       return 0;
+    char buf[8 + 8 + 8 + 128];
+
+    /* Negotiate
+        [ 0 ..   7]   passwd   ("NBDMAGIC")
+        [ 8 ..  15]   magic    (0x00420281861253)
+        [16 ..  23]   size
+        [24 .. 151]   reserved (0)
+     */
+
+    TRACE("Beginning negotiation.");
+    memcpy(buf, "NBDMAGIC", 8);
+    cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
+    cpu_to_be64w((uint64_t*)(buf + 16), size);
+    memset(buf + 24, 0, 128);
+
+    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("write failed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    TRACE("Negotation succeeded.");
+
+    return 0;
 }
 
 int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
                           off_t *size, size_t *blocksize)
 {
-       char buf[256];
-       uint64_t magic, s;
-       uint16_t tmp;
-
-       TRACE("Receiving negotation.");
-
-       if (read_sync(csock, buf, 8) != 8) {
-               LOG("read failed");
-               errno = EINVAL;
-               return -1;
-       }
-
-       buf[8] = '\0';
-       if (strlen(buf) == 0) {
-               LOG("server connection closed");
-               errno = EINVAL;
-               return -1;
-       }
-
-       TRACE("Magic is %c%c%c%c%c%c%c%c",
-             qemu_isprint(buf[0]) ? buf[0] : '.',
-             qemu_isprint(buf[1]) ? buf[1] : '.',
-             qemu_isprint(buf[2]) ? buf[2] : '.',
-             qemu_isprint(buf[3]) ? buf[3] : '.',
-             qemu_isprint(buf[4]) ? buf[4] : '.',
-             qemu_isprint(buf[5]) ? buf[5] : '.',
-             qemu_isprint(buf[6]) ? buf[6] : '.',
-             qemu_isprint(buf[7]) ? buf[7] : '.');
-
-       if (memcmp(buf, "NBDMAGIC", 8) != 0) {
-               LOG("Invalid magic received");
-               errno = EINVAL;
-               return -1;
-       }
-
-       if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
-               LOG("read failed");
-               errno = EINVAL;
-               return -1;
-       }
-       magic = be64_to_cpu(magic);
-       TRACE("Magic is 0x%" PRIx64, magic);
-
-       if (name) {
-               uint32_t reserved = 0;
-               uint32_t opt;
-               uint32_t namesize;
-
-               TRACE("Checking magic (opts_magic)");
-               if (magic != 0x49484156454F5054LL) {
-                       LOG("Bad magic received");
-                       errno = EINVAL;
-                       return -1;
-               }
-               if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
-                       LOG("flags read failed");
-                       errno = EINVAL;
-                       return -1;
-               }
-               *flags = be16_to_cpu(tmp) << 16;
-               /* reserved for future use */
-               if (write_sync(csock, &reserved, sizeof(reserved)) !=
-                   sizeof(reserved)) {
-                       LOG("write failed (reserved)");
-                       errno = EINVAL;
-                       return -1;
-               }
-               /* write the export name */
-               magic = cpu_to_be64(magic);
-               if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
-                       LOG("write failed (magic)");
-                       errno = EINVAL;
-                       return -1;
-               }
-               opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
-               if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
-                       LOG("write failed (opt)");
-                       errno = EINVAL;
-                       return -1;
-               }
-               namesize = cpu_to_be32(strlen(name));
-               if (write_sync(csock, &namesize, sizeof(namesize)) !=
-                   sizeof(namesize)) {
-                       LOG("write failed (namesize)");
-                       errno = EINVAL;
-                       return -1;
-               }
-               if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
-                       LOG("write failed (name)");
-                       errno = EINVAL;
-                       return -1;
-               }
-       } else {
-               TRACE("Checking magic (cli_magic)");
-
-               if (magic != 0x00420281861253LL) {
-                       LOG("Bad magic received");
-                       errno = EINVAL;
-                       return -1;
-               }
-       }
-
-       if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
-               LOG("read failed");
-               errno = EINVAL;
-               return -1;
-       }
-       *size = be64_to_cpu(s);
-       *blocksize = 1024;
-       TRACE("Size is %" PRIu64, *size);
-
-       if (!name) {
-               if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
-                       LOG("read failed (flags)");
-                       errno = EINVAL;
-                       return -1;
-               }
-               *flags = be32_to_cpup(flags);
-       } else {
-               if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
-                       LOG("read failed (tmp)");
-                       errno = EINVAL;
-                       return -1;
-               }
-               *flags |= be32_to_cpu(tmp);
-       }
-       if (read_sync(csock, &buf, 124) != 124) {
-               LOG("read failed (buf)");
-               errno = EINVAL;
-               return -1;
-       }
+    char buf[256];
+    uint64_t magic, s;
+    uint16_t tmp;
+
+    TRACE("Receiving negotation.");
+
+    if (read_sync(csock, buf, 8) != 8) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    buf[8] = '\0';
+    if (strlen(buf) == 0) {
+        LOG("server connection closed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    TRACE("Magic is %c%c%c%c%c%c%c%c",
+          qemu_isprint(buf[0]) ? buf[0] : '.',
+          qemu_isprint(buf[1]) ? buf[1] : '.',
+          qemu_isprint(buf[2]) ? buf[2] : '.',
+          qemu_isprint(buf[3]) ? buf[3] : '.',
+          qemu_isprint(buf[4]) ? buf[4] : '.',
+          qemu_isprint(buf[5]) ? buf[5] : '.',
+          qemu_isprint(buf[6]) ? buf[6] : '.',
+          qemu_isprint(buf[7]) ? buf[7] : '.');
+
+    if (memcmp(buf, "NBDMAGIC", 8) != 0) {
+        LOG("Invalid magic received");
+        errno = EINVAL;
+        return -1;
+    }
+
+    if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+    magic = be64_to_cpu(magic);
+    TRACE("Magic is 0x%" PRIx64, magic);
+
+    if (name) {
+        uint32_t reserved = 0;
+        uint32_t opt;
+        uint32_t namesize;
+
+        TRACE("Checking magic (opts_magic)");
+        if (magic != 0x49484156454F5054LL) {
+            LOG("Bad magic received");
+            errno = EINVAL;
+            return -1;
+        }
+        if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+            LOG("flags read failed");
+            errno = EINVAL;
+            return -1;
+        }
+        *flags = be16_to_cpu(tmp) << 16;
+        /* reserved for future use */
+        if (write_sync(csock, &reserved, sizeof(reserved)) !=
+            sizeof(reserved)) {
+            LOG("write failed (reserved)");
+            errno = EINVAL;
+            return -1;
+        }
+        /* write the export name */
+        magic = cpu_to_be64(magic);
+        if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+            LOG("write failed (magic)");
+            errno = EINVAL;
+            return -1;
+        }
+        opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
+        if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+            LOG("write failed (opt)");
+            errno = EINVAL;
+            return -1;
+        }
+        namesize = cpu_to_be32(strlen(name));
+        if (write_sync(csock, &namesize, sizeof(namesize)) !=
+            sizeof(namesize)) {
+            LOG("write failed (namesize)");
+            errno = EINVAL;
+            return -1;
+        }
+        if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
+            LOG("write failed (name)");
+            errno = EINVAL;
+            return -1;
+        }
+    } else {
+        TRACE("Checking magic (cli_magic)");
+
+        if (magic != 0x00420281861253LL) {
+            LOG("Bad magic received");
+            errno = EINVAL;
+            return -1;
+        }
+    }
+
+    if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+    *size = be64_to_cpu(s);
+    *blocksize = 1024;
+    TRACE("Size is %" PRIu64, *size);
+
+    if (!name) {
+        if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
+            LOG("read failed (flags)");
+            errno = EINVAL;
+            return -1;
+        }
+        *flags = be32_to_cpup(flags);
+    } else {
+        if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+            LOG("read failed (tmp)");
+            errno = EINVAL;
+            return -1;
+        }
+        *flags |= be32_to_cpu(tmp);
+    }
+    if (read_sync(csock, &buf, 124) != 124) {
+        LOG("read failed (buf)");
+        errno = EINVAL;
+        return -1;
+    }
         return 0;
 }
 
 #ifndef _WIN32
 int nbd_init(int fd, int csock, off_t size, size_t blocksize)
 {
-       TRACE("Setting block size to %lu", (unsigned long)blocksize);
+    TRACE("Setting block size to %lu", (unsigned long)blocksize);
 
-       if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
-               int serrno = errno;
-               LOG("Failed setting NBD block size");
-               errno = serrno;
-               return -1;
-       }
+    if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
+        int serrno = errno;
+        LOG("Failed setting NBD block size");
+        errno = serrno;
+        return -1;
+    }
 
         TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
 
-       if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
-               int serrno = errno;
-               LOG("Failed setting size (in blocks)");
-               errno = serrno;
-               return -1;
-       }
+    if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
+        int serrno = errno;
+        LOG("Failed setting size (in blocks)");
+        errno = serrno;
+        return -1;
+    }
 
-       TRACE("Clearing NBD socket");
+    TRACE("Clearing NBD socket");
 
-       if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
-               int serrno = errno;
-               LOG("Failed clearing NBD socket");
-               errno = serrno;
-               return -1;
-       }
+    if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
+        int serrno = errno;
+        LOG("Failed clearing NBD socket");
+        errno = serrno;
+        return -1;
+    }
 
-       TRACE("Setting NBD socket");
+    TRACE("Setting NBD socket");
 
-       if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
-               int serrno = errno;
-               LOG("Failed to set NBD socket");
-               errno = serrno;
-               return -1;
-       }
+    if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
+        int serrno = errno;
+        LOG("Failed to set NBD socket");
+        errno = serrno;
+        return -1;
+    }
 
-       TRACE("Negotiation ended");
+    TRACE("Negotiation ended");
 
-       return 0;
+    return 0;
 }
 
 int nbd_disconnect(int fd)
 {
-       ioctl(fd, NBD_CLEAR_QUE);
-       ioctl(fd, NBD_DISCONNECT);
-       ioctl(fd, NBD_CLEAR_SOCK);
-       return 0;
+    ioctl(fd, NBD_CLEAR_QUE);
+    ioctl(fd, NBD_DISCONNECT);
+    ioctl(fd, NBD_CLEAR_SOCK);
+    return 0;
 }
 
 int nbd_client(int fd)
 {
-       int ret;
-       int serrno;
+    int ret;
+    int serrno;
 
-       TRACE("Doing NBD loop");
+    TRACE("Doing NBD loop");
 
-       ret = ioctl(fd, NBD_DO_IT);
-       serrno = errno;
+    ret = ioctl(fd, NBD_DO_IT);
+    serrno = errno;
 
-       TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
+    TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
 
-       TRACE("Clearing NBD queue");
-       ioctl(fd, NBD_CLEAR_QUE);
+    TRACE("Clearing NBD queue");
+    ioctl(fd, NBD_CLEAR_QUE);
 
-       TRACE("Clearing NBD socket");
-       ioctl(fd, NBD_CLEAR_SOCK);
+    TRACE("Clearing NBD socket");
+    ioctl(fd, NBD_CLEAR_SOCK);
 
-       errno = serrno;
-       return ret;
+    errno = serrno;
+    return ret;
 }
 #else
 int nbd_init(int fd, int csock, off_t size, size_t blocksize)
@@ -531,235 +431,236 @@ int nbd_client(int fd)
 
 int nbd_send_request(int csock, struct nbd_request *request)
 {
-       uint8_t buf[4 + 4 + 8 + 8 + 4];
-
-       cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
-       cpu_to_be32w((uint32_t*)(buf + 4), request->type);
-       cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
-       cpu_to_be64w((uint64_t*)(buf + 16), request->from);
-       cpu_to_be32w((uint32_t*)(buf + 24), request->len);
-
-       TRACE("Sending request to client");
-
-       if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
-               LOG("writing to socket failed");
-               errno = EINVAL;
-               return -1;
-       }
-       return 0;
-}
+    uint8_t buf[4 + 4 + 8 + 8 + 4];
 
+    cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
+    cpu_to_be32w((uint32_t*)(buf + 4), request->type);
+    cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
+    cpu_to_be64w((uint64_t*)(buf + 16), request->from);
+    cpu_to_be32w((uint32_t*)(buf + 24), request->len);
+
+    TRACE("Sending request to client: "
+          "{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
+          request->from, request->len, request->handle, request->type);
+
+    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("writing to socket failed");
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
+}
 
 static int nbd_receive_request(int csock, struct nbd_request *request)
 {
-       uint8_t buf[4 + 4 + 8 + 8 + 4];
-       uint32_t magic;
-
-       if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
-               LOG("read failed");
-               errno = EINVAL;
-               return -1;
-       }
-
-       /* Request
-          [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
-          [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
-          [ 8 .. 15]   handle
-          [16 .. 23]   from
-          [24 .. 27]   len
-        */
-
-       magic = be32_to_cpup((uint32_t*)buf);
-       request->type  = be32_to_cpup((uint32_t*)(buf + 4));
-       request->handle = be64_to_cpup((uint64_t*)(buf + 8));
-       request->from  = be64_to_cpup((uint64_t*)(buf + 16));
-       request->len   = be32_to_cpup((uint32_t*)(buf + 24));
-
-       TRACE("Got request: "
-             "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
-             magic, request->type, request->from, request->len);
-
-       if (magic != NBD_REQUEST_MAGIC) {
-               LOG("invalid magic (got 0x%x)", magic);
-               errno = EINVAL;
-               return -1;
-       }
-       return 0;
+    uint8_t buf[4 + 4 + 8 + 8 + 4];
+    uint32_t magic;
+
+    if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    /* Request
+       [ 0 ..  3]   magic   (NBD_REQUEST_MAGIC)
+       [ 4 ..  7]   type    (0 == READ, 1 == WRITE)
+       [ 8 .. 15]   handle
+       [16 .. 23]   from
+       [24 .. 27]   len
+     */
+
+    magic = be32_to_cpup((uint32_t*)buf);
+    request->type  = be32_to_cpup((uint32_t*)(buf + 4));
+    request->handle = be64_to_cpup((uint64_t*)(buf + 8));
+    request->from  = be64_to_cpup((uint64_t*)(buf + 16));
+    request->len   = be32_to_cpup((uint32_t*)(buf + 24));
+
+    TRACE("Got request: "
+          "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
+          magic, request->type, request->from, request->len);
+
+    if (magic != NBD_REQUEST_MAGIC) {
+        LOG("invalid magic (got 0x%x)", magic);
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
 }
 
 int nbd_receive_reply(int csock, struct nbd_reply *reply)
 {
-       uint8_t buf[NBD_REPLY_SIZE];
-       uint32_t magic;
-
-       memset(buf, 0xAA, sizeof(buf));
-
-       if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
-               LOG("read failed");
-               errno = EINVAL;
-               return -1;
-       }
-
-       /* Reply
-          [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
-          [ 4 ..  7]    error   (0 == no error)
-          [ 7 .. 15]    handle
-        */
-
-       magic = be32_to_cpup((uint32_t*)buf);
-       reply->error  = be32_to_cpup((uint32_t*)(buf + 4));
-       reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
-
-       TRACE("Got reply: "
-             "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
-             magic, reply->error, reply->handle);
-
-       if (magic != NBD_REPLY_MAGIC) {
-               LOG("invalid magic (got 0x%x)", magic);
-               errno = EINVAL;
-               return -1;
-       }
-       return 0;
+    uint8_t buf[NBD_REPLY_SIZE];
+    uint32_t magic;
+
+    memset(buf, 0xAA, sizeof(buf));
+
+    if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("read failed");
+        errno = EINVAL;
+        return -1;
+    }
+
+    /* Reply
+       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+       [ 4 ..  7]    error   (0 == no error)
+       [ 7 .. 15]    handle
+     */
+
+    magic = be32_to_cpup((uint32_t*)buf);
+    reply->error  = be32_to_cpup((uint32_t*)(buf + 4));
+    reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
+
+    TRACE("Got reply: "
+          "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
+          magic, reply->error, reply->handle);
+
+    if (magic != NBD_REPLY_MAGIC) {
+        LOG("invalid magic (got 0x%x)", magic);
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
 }
 
 static int nbd_send_reply(int csock, struct nbd_reply *reply)
 {
-       uint8_t buf[4 + 4 + 8];
-
-       /* Reply
-          [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
-          [ 4 ..  7]    error   (0 == no error)
-          [ 7 .. 15]    handle
-        */
-       cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
-       cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
-       cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
-
-       TRACE("Sending response to client");
-
-       if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
-               LOG("writing to socket failed");
-               errno = EINVAL;
-               return -1;
-       }
-       return 0;
+    uint8_t buf[4 + 4 + 8];
+
+    /* Reply
+       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+       [ 4 ..  7]    error   (0 == no error)
+       [ 7 .. 15]    handle
+     */
+    cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
+    cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
+    cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
+
+    TRACE("Sending response to client");
+
+    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+        LOG("writing to socket failed");
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
 }
 
 int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
              off_t *offset, bool readonly, uint8_t *data, int data_size)
 {
-       struct nbd_request request;
-       struct nbd_reply reply;
-
-       TRACE("Reading request.");
-
-       if (nbd_receive_request(csock, &request) == -1)
-               return -1;
-
-       if (request.len + NBD_REPLY_SIZE > data_size) {
-               LOG("len (%u) is larger than max len (%u)",
-                   request.len + NBD_REPLY_SIZE, data_size);
-               errno = EINVAL;
-               return -1;
-       }
-
-       if ((request.from + request.len) < request.from) {
-               LOG("integer overflow detected! "
-                   "you're probably being attacked");
-               errno = EINVAL;
-               return -1;
-       }
-
-       if ((request.from + request.len) > size) {
-               LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
-                   ", Offset: %" PRIu64 "\n",
+    struct nbd_request request;
+    struct nbd_reply reply;
+
+    TRACE("Reading request.");
+
+    if (nbd_receive_request(csock, &request) == -1)
+        return -1;
+
+    if (request.len + NBD_REPLY_SIZE > data_size) {
+        LOG("len (%u) is larger than max len (%u)",
+            request.len + NBD_REPLY_SIZE, data_size);
+        errno = EINVAL;
+        return -1;
+    }
+
+    if ((request.from + request.len) < request.from) {
+        LOG("integer overflow detected! "
+            "you're probably being attacked");
+        errno = EINVAL;
+        return -1;
+    }
+
+    if ((request.from + request.len) > size) {
+            LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
+            ", Offset: %" PRIu64 "\n",
                     request.from, request.len, (uint64_t)size, dev_offset);
-               LOG("requested operation past EOF--bad client?");
-               errno = EINVAL;
-               return -1;
-       }
-
-       TRACE("Decoding type");
-
-       reply.handle = request.handle;
-       reply.error = 0;
-
-       switch (request.type) {
-       case NBD_CMD_READ:
-               TRACE("Request type is READ");
-
-               if (bdrv_read(bs, (request.from + dev_offset) / 512,
-                             data + NBD_REPLY_SIZE,
-                             request.len / 512) == -1) {
-                       LOG("reading from file failed");
-                       errno = EINVAL;
-                       return -1;
-               }
-               *offset += request.len;
-
-               TRACE("Read %u byte(s)", request.len);
-
-               /* Reply
-                  [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
-                  [ 4 ..  7]    error   (0 == no error)
-                  [ 7 .. 15]    handle
-                */
-
-               cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC);
-               cpu_to_be32w((uint32_t*)(data + 4), reply.error);
-               cpu_to_be64w((uint64_t*)(data + 8), reply.handle);
-
-               TRACE("Sending data to client");
-
-               if (write_sync(csock, data,
-                              request.len + NBD_REPLY_SIZE) !=
-                              request.len + NBD_REPLY_SIZE) {
-                       LOG("writing to socket failed");
-                       errno = EINVAL;
-                       return -1;
-               }
-               break;
-       case NBD_CMD_WRITE:
-               TRACE("Request type is WRITE");
-
-               TRACE("Reading %u byte(s)", request.len);
-
-               if (read_sync(csock, data, request.len) != request.len) {
-                       LOG("reading from socket failed");
-                       errno = EINVAL;
-                       return -1;
-               }
-
-               if (readonly) {
-                       TRACE("Server is read-only, return error");
-                       reply.error = 1;
-               } else {
-                       TRACE("Writing to device");
-
-                       if (bdrv_write(bs, (request.from + dev_offset) / 512,
-                                      data, request.len / 512) == -1) {
-                               LOG("writing to file failed");
-                               errno = EINVAL;
-                               return -1;
-                       }
-
-                       *offset += request.len;
-               }
-
-               if (nbd_send_reply(csock, &reply) == -1)
-                       return -1;
-               break;
-       case NBD_CMD_DISC:
-               TRACE("Request type is DISCONNECT");
-               errno = 0;
-               return 1;
-       default:
-               LOG("invalid request type (%u) received", request.type);
-               errno = EINVAL;
-               return -1;
-       }
-
-       TRACE("Request/Reply complete");
-
-       return 0;
+        LOG("requested operation past EOF--bad client?");
+        errno = EINVAL;
+        return -1;
+    }
+
+    TRACE("Decoding type");
+
+    reply.handle = request.handle;
+    reply.error = 0;
+
+    switch (request.type) {
+    case NBD_CMD_READ:
+        TRACE("Request type is READ");
+
+        if (bdrv_read(bs, (request.from + dev_offset) / 512,
+                  data + NBD_REPLY_SIZE,
+                  request.len / 512) == -1) {
+            LOG("reading from file failed");
+            errno = EINVAL;
+            return -1;
+        }
+        *offset += request.len;
+
+        TRACE("Read %u byte(s)", request.len);
+
+        /* Reply
+           [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+           [ 4 ..  7]    error   (0 == no error)
+           [ 7 .. 15]    handle
+         */
+
+        cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC);
+        cpu_to_be32w((uint32_t*)(data + 4), reply.error);
+        cpu_to_be64w((uint64_t*)(data + 8), reply.handle);
+
+        TRACE("Sending data to client");
+
+        if (write_sync(csock, data,
+                   request.len + NBD_REPLY_SIZE) !=
+                   request.len + NBD_REPLY_SIZE) {
+            LOG("writing to socket failed");
+            errno = EINVAL;
+            return -1;
+        }
+        break;
+    case NBD_CMD_WRITE:
+        TRACE("Request type is WRITE");
+
+        TRACE("Reading %u byte(s)", request.len);
+
+        if (read_sync(csock, data, request.len) != request.len) {
+            LOG("reading from socket failed");
+            errno = EINVAL;
+            return -1;
+        }
+
+        if (readonly) {
+            TRACE("Server is read-only, return error");
+            reply.error = 1;
+        } else {
+            TRACE("Writing to device");
+
+            if (bdrv_write(bs, (request.from + dev_offset) / 512,
+                       data, request.len / 512) == -1) {
+                LOG("writing to file failed");
+                errno = EINVAL;
+                return -1;
+            }
+
+            *offset += request.len;
+        }
+
+        if (nbd_send_reply(csock, &reply) == -1)
+            return -1;
+        break;
+    case NBD_CMD_DISC:
+        TRACE("Request type is DISCONNECT");
+        errno = 0;
+        return 1;
+    default:
+        LOG("invalid request type (%u) received", request.type);
+        errno = EINVAL;
+        return -1;
+    }
+
+    TRACE("Request/Reply complete");
+
+    return 0;
 }
diff --git a/nbd.h b/nbd.h
index fc3a5944f4a6b10fad89dd0c5e59b7b5135cf639..b38d0d08de2d80bdf545251f8b02921234b973c5 100644 (file)
--- a/nbd.h
+++ b/nbd.h
 #include <sys/types.h>
 
 #include <qemu-common.h>
+
 #include "block_int.h"
 
 struct nbd_request {
+    uint32_t magic;
     uint32_t type;
     uint64_t handle;
     uint64_t from;
     uint32_t len;
-};
+} __attribute__ ((__packed__));
 
 struct nbd_reply {
+    uint32_t magic;
     uint32_t error;
     uint64_t handle;
-};
+} __attribute__ ((__packed__));
 
 enum {
     NBD_CMD_READ = 0,
@@ -47,6 +50,8 @@ enum {
 size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
 int tcp_socket_outgoing(const char *address, uint16_t port);
 int tcp_socket_incoming(const char *address, uint16_t port);
+int tcp_socket_outgoing_spec(const char *address_and_port);
+int tcp_socket_incoming_spec(const char *address_and_port);
 int unix_socket_outgoing(const char *path);
 int unix_socket_incoming(const char *path);
 
diff --git a/net-checksum.c b/net-checksum.c
deleted file mode 100644 (file)
index 4956c5c..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- *  IP checksumming functions.
- *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
- *
- *  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; under version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/hw.h"
-#include "net.h"
-
-#define PROTO_TCP  6
-#define PROTO_UDP 17
-
-uint32_t net_checksum_add(int len, uint8_t *buf)
-{
-    uint32_t sum = 0;
-    int i;
-
-    for (i = 0; i < len; i++) {
-       if (i & 1)
-           sum += (uint32_t)buf[i];
-       else
-           sum += (uint32_t)buf[i] << 8;
-    }
-    return sum;
-}
-
-uint16_t net_checksum_finish(uint32_t sum)
-{
-    while (sum>>16)
-       sum = (sum & 0xFFFF)+(sum >> 16);
-    return ~sum;
-}
-
-uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto,
-                             uint8_t *addrs, uint8_t *buf)
-{
-    uint32_t sum = 0;
-
-    sum += net_checksum_add(length, buf);         // payload
-    sum += net_checksum_add(8, addrs);            // src + dst address
-    sum += proto + length;                        // protocol & length
-    return net_checksum_finish(sum);
-}
-
-void net_checksum_calculate(uint8_t *data, int length)
-{
-    int hlen, plen, proto, csum_offset;
-    uint16_t csum;
-
-    if ((data[14] & 0xf0) != 0x40)
-       return; /* not IPv4 */
-    hlen  = (data[14] & 0x0f) * 4;
-    plen  = (data[16] << 8 | data[17]) - hlen;
-    proto = data[23];
-
-    switch (proto) {
-    case PROTO_TCP:
-       csum_offset = 16;
-       break;
-    case PROTO_UDP:
-       csum_offset = 6;
-       break;
-    default:
-       return;
-    }
-
-    if (plen < csum_offset+2)
-       return;
-
-    data[14+hlen+csum_offset]   = 0;
-    data[14+hlen+csum_offset+1] = 0;
-    csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen);
-    data[14+hlen+csum_offset]   = csum >> 8;
-    data[14+hlen+csum_offset+1] = csum & 0xff;
-}
diff --git a/net.c b/net.c
index ddcca9752d8df0cdaa8aab0ca2eb8f818df24989..4f777c3dac05e2ea584ae7db02410607fd729fca 100644 (file)
--- a/net.c
+++ b/net.c
@@ -32,7 +32,6 @@
 #include "net/vde.h"
 #include "net/util.h"
 #include "monitor.h"
-#include "sysemu.h"
 #include "qemu-common.h"
 #include "qemu_socket.h"
 #include "hw/qdev.h"
@@ -1305,12 +1304,30 @@ void net_check_clients(void)
 {
     VLANState *vlan;
     VLANClientState *vc;
-    int has_nic = 0, has_host_dev = 0;
+    int seen_nics = 0;
+
+    /* Don't warn about the default network setup that you get if
+     * no command line -net options are specified. There are two
+     * cases that we would otherwise complain about:
+     * (1) board doesn't support a NIC but the implicit "-net nic"
+     * requested one; we'd otherwise complain about more NICs being
+     * specified than we support, and also that the vlan set up by
+     * the implicit "-net user" didn't have any NICs connected to it
+     * (2) CONFIG_SLIRP not set: we'd otherwise complain about the
+     * implicit "-net nic" setting up a nic that wasn't connected to
+     * anything.
+     */
+    if (default_net) {
+        return;
+    }
 
     QTAILQ_FOREACH(vlan, &vlans, next) {
+        int has_nic = 0, has_host_dev = 0;
+
         QTAILQ_FOREACH(vc, &vlan->clients, next) {
             switch (vc->info->type) {
             case NET_CLIENT_TYPE_NIC:
+                seen_nics++;
                 has_nic = 1;
                 break;
             case NET_CLIENT_TYPE_SLIRP:
@@ -1330,12 +1347,26 @@ void net_check_clients(void)
                     vlan->id);
     }
     QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (vc->info->type == NET_CLIENT_TYPE_NIC) {
+            seen_nics++;
+        }
         if (!vc->peer) {
             fprintf(stderr, "Warning: %s %s has no peer\n",
                     vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
                     vc->name);
         }
     }
+    if (seen_nics != nb_nics) {
+        /* Number of NICs requested by user on command line doesn't match
+         * the number the model actually registered with us.
+         * This will generally only happen for models of embedded boards
+         * with no PCI bus or similar. PCI based machines can instantiate
+         * all requested NICs as PCI devices but usually embedded boards
+         * only have a single NIC.
+         */
+        fprintf(stderr, "Warning: more nics requested than this machine "
+                "supports; some have been ignored\n");
+    }
 }
 
 static int net_init_client(QemuOpts *opts, void *dummy)
index 83eda0fcc61cff722c2f48629be4a63c49057b8a..0d0cbb2591ef31bc36ddecb00ba2cbc57bd6da96 100644 (file)
@@ -24,9 +24,9 @@
 
 #include "dump.h"
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "qemu-error.h"
 #include "qemu-log.h"
+#include "qemu-timer.h"
 
 typedef struct DumpState {
     VLANClientState nc;
index b41c60a39bb65d8bbb7c4143ddde6039aa90164c..e387a116add022b75510ed6ba772649c6e208f6c 100644 (file)
@@ -30,7 +30,6 @@
 #endif
 #include "net.h"
 #include "monitor.h"
-#include "sysemu.h"
 #include "qemu_socket.h"
 #include "slirp/libslirp.h"
 
index 0b46fa6405b2cd3d304ba5cd5709394c429584c0..ac48ab2f0a91509677a0bd086f9353922643569c 100644 (file)
--- a/net/vde.c
+++ b/net/vde.c
@@ -31,7 +31,6 @@
 #include "qemu-char.h"
 #include "qemu-common.h"
 #include "qemu-option.h"
-#include "sysemu.h"
 
 typedef struct VDEState {
     VLANClientState nc;
index eb49e2f17789135ec53e28ed5af7cbeb043e7360..320419793a5c95d62be0f4a1fbc91b710f1bb30f 100644 (file)
@@ -67,11 +67,6 @@ static void termsig_handler(int signal, siginfo_t *info, void *c)
     qemu_system_killed(info->si_signo, info->si_pid);
 }
 
-static void sigchld_handler(int signal)
-{
-    waitpid(-1, NULL, WNOHANG);
-}
-
 void os_setup_signal_handling(void)
 {
     struct sigaction act;
@@ -82,10 +77,6 @@ void os_setup_signal_handling(void)
     sigaction(SIGINT,  &act, NULL);
     sigaction(SIGHUP,  &act, NULL);
     sigaction(SIGTERM, &act, NULL);
-
-    act.sa_handler = sigchld_handler;
-    act.sa_flags = SA_NOCLDSTOP;
-    sigaction(SIGCHLD, &act, NULL);
 }
 
 /* Find a likely location for support files using the location of the binary.
diff --git a/osdep.c b/osdep.c
index 327583baf73a8b1b10f3b6456bcd80a7861a49e7..56e6963f1572589d1dbfc3bda8915ae6368ffd5a 100644 (file)
--- a/osdep.c
+++ b/osdep.c
@@ -46,7 +46,6 @@ extern int madvise(caddr_t, size_t, int);
 
 #include "qemu-common.h"
 #include "trace.h"
-#include "sysemu.h"
 #include "qemu_socket.h"
 
 int qemu_madvise(void *addr, size_t len, int advice)
index 3fc09449fac44ae08d1df1c65f0747ed0a724c07..fe221a940ff93d52468c28fd4bee04377dc17487 100644 (file)
   The included image for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32
   and Sparc64 are built from OpenBIOS SVN revision 1018.
 
-- The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0
+- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
+  implementation for certain IBM POWER hardware.  The sources are at
+  https://github.com/dgibson/SLOF, and the image currently in qemu is
+  built from git tag qemu-slof-20110323.
 
-  e1000 8086:100E
-  eepro100 8086:1209 (also used for 8086:1229 and 8086:2449)
-  ns8390 1050:0940
-  pcnet32 1022:2000
-  rtl8139 10ec:8139
-  virtio 1af4:1000
+- The PXE roms come from the iPXE project. Built with BANNER_TIME 0.
+  Sources available at http://ipxe.org.  Vendor:Device ID -> ROM mapping:
 
-  http://rom-o-matic.net/
+       8086:100e -> pxe-e1000.rom
+       8086:1209 -> pxe-eepro100.rom
+       1050:0940 -> pxe-ne2k_pci.rom
+       1022:2000 -> pxe-pcnet.rom
+       10ec:8139 -> pxe-rtl8139.rom
+       1af4:1000 -> pxe-virtio.rom
 
 - The S390 zipl loader is an addition to the official IBM s390-tools
   package. That fork is maintained in its own git repository at:
diff --git a/pc-bios/gpxe-eepro100-80861209.rom b/pc-bios/gpxe-eepro100-80861209.rom
deleted file mode 100644 (file)
index 2ca59ec..0000000
Binary files a/pc-bios/gpxe-eepro100-80861209.rom and /dev/null differ
diff --git a/pc-bios/pxe-e1000.bin b/pc-bios/pxe-e1000.bin
deleted file mode 100644 (file)
index 7ac744e..0000000
Binary files a/pc-bios/pxe-e1000.bin and /dev/null differ
diff --git a/pc-bios/pxe-e1000.rom b/pc-bios/pxe-e1000.rom
new file mode 100644 (file)
index 0000000..2e5f8b2
Binary files /dev/null and b/pc-bios/pxe-e1000.rom differ
diff --git a/pc-bios/pxe-eepro100.rom b/pc-bios/pxe-eepro100.rom
new file mode 100644 (file)
index 0000000..d292e8f
Binary files /dev/null and b/pc-bios/pxe-eepro100.rom differ
diff --git a/pc-bios/pxe-ne2k_pci.bin b/pc-bios/pxe-ne2k_pci.bin
deleted file mode 100644 (file)
index 5cb68ab..0000000
Binary files a/pc-bios/pxe-ne2k_pci.bin and /dev/null differ
diff --git a/pc-bios/pxe-ne2k_pci.rom b/pc-bios/pxe-ne2k_pci.rom
new file mode 100644 (file)
index 0000000..62010cb
Binary files /dev/null and b/pc-bios/pxe-ne2k_pci.rom differ
diff --git a/pc-bios/pxe-pcnet.bin b/pc-bios/pxe-pcnet.bin
deleted file mode 100644 (file)
index 7a54bab..0000000
Binary files a/pc-bios/pxe-pcnet.bin and /dev/null differ
diff --git a/pc-bios/pxe-pcnet.rom b/pc-bios/pxe-pcnet.rom
new file mode 100644 (file)
index 0000000..512d6d4
Binary files /dev/null and b/pc-bios/pxe-pcnet.rom differ
diff --git a/pc-bios/pxe-rtl8139.bin b/pc-bios/pxe-rtl8139.bin
deleted file mode 100644 (file)
index db7d76d..0000000
Binary files a/pc-bios/pxe-rtl8139.bin and /dev/null differ
diff --git a/pc-bios/pxe-rtl8139.rom b/pc-bios/pxe-rtl8139.rom
new file mode 100644 (file)
index 0000000..67c77fb
Binary files /dev/null and b/pc-bios/pxe-rtl8139.rom differ
diff --git a/pc-bios/pxe-virtio.bin b/pc-bios/pxe-virtio.bin
deleted file mode 100644 (file)
index 6dde514..0000000
Binary files a/pc-bios/pxe-virtio.bin and /dev/null differ
diff --git a/pc-bios/pxe-virtio.rom b/pc-bios/pxe-virtio.rom
new file mode 100644 (file)
index 0000000..b1ec909
Binary files /dev/null and b/pc-bios/pxe-virtio.rom differ
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
new file mode 100644 (file)
index 0000000..22c4c7f
Binary files /dev/null and b/pc-bios/slof.bin differ
diff --git a/pc-bios/spapr-rtas.bin b/pc-bios/spapr-rtas.bin
new file mode 100644 (file)
index 0000000..fc24c8e
Binary files /dev/null and b/pc-bios/spapr-rtas.bin differ
diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile
new file mode 100644 (file)
index 0000000..dc8b23e
--- /dev/null
@@ -0,0 +1,24 @@
+all: build-all
+# Dummy command so that make thinks it has done something
+       @true
+
+include ../../config-host.mak
+include $(SRC_PATH)/rules.mak
+
+$(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas)
+
+.PHONY : all clean build-all
+
+#CFLAGS += -I$(SRC_PATH)
+#QEMU_CFLAGS = $(CFLAGS)
+
+build-all: spapr-rtas.bin
+
+%.img: %.o
+       $(call quiet-command,$(CC) -nostdlib -o $@ $<,"  Building $(TARGET_DIR)$@")
+
+%.bin: %.img
+       $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"  Building $(TARGET_DIR)$@")
+
+clean:
+       rm -f *.o *.d *.img *.bin *~
diff --git a/pc-bios/spapr-rtas/spapr-rtas.S b/pc-bios/spapr-rtas/spapr-rtas.S
new file mode 100644 (file)
index 0000000..903bec2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Trivial in-partition RTAS implementation, based on a hypercall
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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.
+ *
+ */
+
+#define KVMPPC_HCALL_BASE       0xf000
+#define KVMPPC_H_RTAS           (KVMPPC_HCALL_BASE + 0x0)
+
+.globl _start
+_start:
+       mr      4,3
+       lis     3,KVMPPC_H_RTAS@h
+       ori     3,3,KVMPPC_H_RTAS@l
+       sc      1
+       blr
index 03858d4ef7aaef0d88ffaa4fb7274db2e8ec6bcc..5e04a20b8c4dd04ff14be2679439f51d237873d9 100644 (file)
@@ -197,9 +197,9 @@ void qemu_chr_add_handlers(CharDriverState *s,
                            IOEventHandler *fd_event,
                            void *opaque)
 {
-    if (!opaque) {
+    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
         /* chr driver being released. */
-        s->assigned = 0;
+        ++s->avail_connections;
     }
     s->chr_can_read = fd_can_read;
     s->chr_read = fd_read;
@@ -480,6 +480,9 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
     chr->chr_write = mux_chr_write;
     chr->chr_update_read_handler = mux_chr_update_read_handler;
     chr->chr_accept_input = mux_chr_accept_input;
+    /* Frontend guest-open / -close notification is not support with muxes */
+    chr->chr_guest_open = NULL;
+    chr->chr_guest_close = NULL;
 
     /* Muxes are always open on creation */
     qemu_chr_generic_open(chr);
@@ -2544,7 +2547,10 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
         snprintf(base->label, len, "%s-base", qemu_opts_id(opts));
         chr = qemu_chr_open_mux(base);
         chr->filename = base->filename;
+        chr->avail_connections = MAX_MUX;
         QTAILQ_INSERT_TAIL(&chardevs, chr, next);
+    } else {
+        chr->avail_connections = 1;
     }
     chr->label = qemu_strdup(qemu_opts_id(opts));
     return chr;
@@ -2579,6 +2585,20 @@ void qemu_chr_set_echo(struct CharDriverState *chr, bool echo)
     }
 }
 
+void qemu_chr_guest_open(struct CharDriverState *chr)
+{
+    if (chr->chr_guest_open) {
+        chr->chr_guest_open(chr);
+    }
+}
+
+void qemu_chr_guest_close(struct CharDriverState *chr)
+{
+    if (chr->chr_guest_close) {
+        chr->chr_guest_close(chr);
+    }
+}
+
 void qemu_chr_close(CharDriverState *chr)
 {
     QTAILQ_REMOVE(&chardevs, chr, next);
index fb96eef3de73f0cbc7c29d473c2ca2296147b308..892c6da9aa153dc1f348ef7ad1c83840af744da8 100644 (file)
@@ -65,12 +65,14 @@ struct CharDriverState {
     void (*chr_close)(struct CharDriverState *chr);
     void (*chr_accept_input)(struct CharDriverState *chr);
     void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
+    void (*chr_guest_open)(struct CharDriverState *chr);
+    void (*chr_guest_close)(struct CharDriverState *chr);
     void *opaque;
     QEMUBH *bh;
     char *label;
     char *filename;
     int opened;
-    int assigned; /* chardev assigned to a device */
+    int avail_connections;
     QTAILQ_ENTRY(CharDriverState) next;
 };
 
@@ -79,6 +81,8 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
                                     void (*init)(struct CharDriverState *s));
 CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s));
 void qemu_chr_set_echo(struct CharDriverState *chr, bool echo);
+void qemu_chr_guest_open(struct CharDriverState *chr);
+void qemu_chr_guest_close(struct CharDriverState *chr);
 void qemu_chr_close(CharDriverState *chr);
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
     GCC_FMT_ATTR(2, 3);
index 7a96dd14e82a4c22c0ebd304a9f9d5017f459bbc..f9f705da857bbc31d25a5d6670e95f236573a039 100644 (file)
@@ -12,6 +12,7 @@
 #endif
 
 #define QEMU_BUILD_BUG_ON(x) typedef char __build_bug_on__##__LINE__[(x)?-1:1];
+#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
 
 typedef struct QEMUTimer QEMUTimer;
 typedef struct QEMUFile QEMUFile;
@@ -39,6 +40,14 @@ typedef struct Monitor Monitor;
 #include <sys/time.h>
 #include <assert.h>
 
+#ifdef _WIN32
+#include "qemu-os-win32.h"
+#endif
+
+#ifdef CONFIG_POSIX
+#include "qemu-os-posix.h"
+#endif
+
 #ifndef O_LARGEFILE
 #define O_LARGEFILE 0
 #endif
@@ -214,6 +223,7 @@ ssize_t qemu_write_full(int fd, const void *buf, size_t count)
 void qemu_set_cloexec(int fd);
 
 #ifndef _WIN32
+int qemu_add_child_watch(pid_t pid);
 int qemu_eventfd(int pipefd[2]);
 int qemu_pipe(int pipefd[2]);
 #endif
@@ -227,6 +237,9 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
 typedef int IOCanReadHandler(void *opaque);
 typedef void IOHandler(void *opaque);
 
+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);
+
 struct ParallelIOArg {
     void *buffer;
     int count;
@@ -294,6 +307,7 @@ void qemu_notify_event(void);
 void qemu_cpu_kick(void *env);
 void qemu_cpu_kick_self(void);
 int qemu_cpu_is_self(void *env);
+bool all_cpu_threads_idle(void);
 
 /* work queue */
 struct qemu_work_item {
@@ -330,6 +344,20 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
 void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
                             size_t skip);
 
+void qemu_progress_init(int enabled, float min_skip);
+void qemu_progress_end(void);
+void qemu_progress_print(float percent, int max);
+
+#define QEMU_FILE_TYPE_BIOS   0
+#define QEMU_FILE_TYPE_KEYMAP 1
+char *qemu_find_file(int type, const char *name);
+
+/* OS specific functions */
+void os_setup_early_signal_handling(void);
+char *os_find_datadir(const char *argv0);
+void os_parse_cmd_args(int index, const char *optarg);
+void os_pidfile_error(void);
+
 /* Convert a byte between binary and BCD.  */
 static inline uint8_t to_bcd(uint8_t val)
 {
index 323d3c2c292721e3ab4a8d19e4dc8c9137fd22ea..14d34194d09e7df367d91f55d135bf8260173248 100644 (file)
@@ -2,7 +2,6 @@
 #include "qemu-error.h"
 #include "qemu-option.h"
 #include "qemu-config.h"
-#include "sysemu.h"
 #include "hw/qdev.h"
 
 static QemuOptsList qemu_drive_opts = {
index 5a35e7c1c2c0f9fa63fcf4bccba8a804af09619c..41c191d528863163c5f48fcb44569d7c11ebc5ad 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <stdio.h>
 #include "monitor.h"
-#include "sysemu.h"
 
 /*
  * Print to current monitor if we have one, else to stderr.
index 6c7176f8b4643fe120f9abe4bf0258a41d558f05..3072d383cfc51a9a526d38463ce58fe531705be3 100644 (file)
@@ -28,7 +28,7 @@ STEXI
 ETEXI
 
 DEF("convert", img_convert,
-    "convert [-c] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
+    "convert [-c] [-p] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
 STEXI
 @item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 ETEXI
@@ -46,7 +46,7 @@ STEXI
 ETEXI
 
 DEF("rebase", img_rebase,
-    "rebase [-f fmt] [-u] -b backing_file [-F backing_fmt] filename")
+    "rebase [-f fmt] [-p] [-u] -b backing_file [-F backing_fmt] filename")
 STEXI
 @item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
 ETEXI
index 7e3cc4cbd5cc57086703227a4121af11db722e48..e8251234b1508a2bab0749a5896ece468a2a12fc 100644 (file)
@@ -77,6 +77,7 @@ static void help(void)
            "       match exactly. The image doesn't need a working backing file before\n"
            "       rebasing in this case (useful for renaming the backing file)\n"
            "  '-h' with or without a command shows this help and lists the supported formats\n"
+           "  '-p' show progress of command (only certain commands)\n"
            "\n"
            "Parameters to snapshot subcommand:\n"
            "  'snapshot' is the name of the snapshot to create, apply or delete\n"
@@ -567,6 +568,7 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
 static int img_convert(int argc, char **argv)
 {
     int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
+    int progress = 0;
     const char *fmt, *out_fmt, *out_baseimg, *out_filename;
     BlockDriver *drv, *proto_drv;
     BlockDriverState **bs = NULL, *out_bs = NULL;
@@ -579,13 +581,14 @@ static int img_convert(int argc, char **argv)
     QEMUOptionParameter *out_baseimg_param;
     char *options = NULL;
     const char *snapshot_name = NULL;
+    float local_progress;
 
     fmt = NULL;
     out_fmt = "raw";
     out_baseimg = NULL;
     compress = 0;
     for(;;) {
-        c = getopt(argc, argv, "f:O:B:s:hce6o:");
+        c = getopt(argc, argv, "f:O:B:s:hce6o:p");
         if (c == -1) {
             break;
         }
@@ -620,6 +623,9 @@ static int img_convert(int argc, char **argv)
         case 's':
             snapshot_name = optarg;
             break;
+        case 'p':
+            progress = 1;
+            break;
         }
     }
 
@@ -642,6 +648,9 @@ static int img_convert(int argc, char **argv)
         goto out;
     }
         
+    qemu_progress_init(progress, 2.0);
+    qemu_progress_print(0, 100);
+
     bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *));
 
     total_sectors = 0;
@@ -773,6 +782,11 @@ static int img_convert(int argc, char **argv)
         }
         cluster_sectors = cluster_size >> 9;
         sector_num = 0;
+
+        nb_sectors = total_sectors;
+        local_progress = (float)100 /
+            (nb_sectors / MIN(nb_sectors, (cluster_sectors)));
+
         for(;;) {
             int64_t bs_num;
             int remainder;
@@ -832,6 +846,7 @@ static int img_convert(int argc, char **argv)
                 }
             }
             sector_num += n;
+            qemu_progress_print(local_progress, 100);
         }
         /* signal EOF to align */
         bdrv_write_compressed(out_bs, 0, NULL, 0);
@@ -839,6 +854,10 @@ static int img_convert(int argc, char **argv)
         int has_zero_init = bdrv_has_zero_init(out_bs);
 
         sector_num = 0; // total number of sectors converted so far
+        nb_sectors = total_sectors - sector_num;
+        local_progress = (float)100 /
+            (nb_sectors / MIN(nb_sectors, (IO_BUF_SIZE / 512)));
+
         for(;;) {
             nb_sectors = total_sectors - sector_num;
             if (nb_sectors <= 0) {
@@ -912,9 +931,11 @@ static int img_convert(int argc, char **argv)
                 n -= n1;
                 buf1 += n1 * 512;
             }
+            qemu_progress_print(local_progress, 100);
         }
     }
 out:
+    qemu_progress_end();
     free_option_parameters(create_options);
     free_option_parameters(param);
     qemu_free(buf);
@@ -1184,6 +1205,7 @@ static int img_rebase(int argc, char **argv)
     const char *fmt, *out_basefmt, *out_baseimg;
     int c, flags, ret;
     int unsafe = 0;
+    int progress = 0;
 
     /* Parse commandline parameters */
     fmt = NULL;
@@ -1191,7 +1213,7 @@ static int img_rebase(int argc, char **argv)
     out_basefmt = NULL;
 
     for(;;) {
-        c = getopt(argc, argv, "uhf:F:b:");
+        c = getopt(argc, argv, "uhf:F:b:p");
         if (c == -1) {
             break;
         }
@@ -1212,14 +1234,20 @@ static int img_rebase(int argc, char **argv)
         case 'u':
             unsafe = 1;
             break;
+        case 'p':
+            progress = 1;
+            break;
         }
     }
 
-    if ((optind >= argc) || !out_baseimg) {
+    if ((optind >= argc) || (!unsafe && !out_baseimg)) {
         help();
     }
     filename = argv[optind++];
 
+    qemu_progress_init(progress, 2.0);
+    qemu_progress_print(0, 100);
+
     /*
      * Open the images.
      *
@@ -1295,12 +1323,15 @@ static int img_rebase(int argc, char **argv)
         int n;
         uint8_t * buf_old;
         uint8_t * buf_new;
+        float local_progress;
 
         buf_old = qemu_malloc(IO_BUF_SIZE);
         buf_new = qemu_malloc(IO_BUF_SIZE);
 
         bdrv_get_geometry(bs, &num_sectors);
 
+        local_progress = (float)100 /
+            (num_sectors / MIN(num_sectors, (IO_BUF_SIZE / 512)));
         for (sector = 0; sector < num_sectors; sector += n) {
 
             /* How many sectors can we handle with the next read? */
@@ -1348,6 +1379,7 @@ static int img_rebase(int argc, char **argv)
 
                 written += pnum;
             }
+            qemu_progress_print(local_progress, 100);
         }
 
         qemu_free(buf_old);
@@ -1368,6 +1400,7 @@ static int img_rebase(int argc, char **argv)
             out_baseimg, strerror(-ret));
     }
 
+    qemu_progress_print(100, 0);
     /*
      * TODO At this point it is possible to check if any clusters that are
      * allocated in the COW file are the same in the backing file. If so, they
@@ -1375,10 +1408,15 @@ static int img_rebase(int argc, char **argv)
      * backing file, in case of a crash this would lead to corruption.
      */
 out:
+    qemu_progress_end();
     /* Cleanup */
     if (!unsafe) {
-        bdrv_delete(bs_old_backing);
-        bdrv_delete(bs_new_backing);
+        if (bs_old_backing != NULL) {
+            bdrv_delete(bs_old_backing);
+        }
+        if (bs_new_backing != NULL) {
+            bdrv_delete(bs_new_backing);
+        }
     }
 
     bdrv_delete(bs);
@@ -1404,6 +1442,16 @@ static int img_resize(int argc, char **argv)
         { NULL }
     };
 
+    /* Remove size from argv manually so that negative numbers are not treated
+     * as options by getopt. */
+    if (argc < 3) {
+        help();
+        return 1;
+    }
+
+    size = argv[--argc];
+
+    /* Parse getopt arguments */
     fmt = NULL;
     for(;;) {
         c = getopt(argc, argv, "f:h");
@@ -1420,11 +1468,10 @@ static int img_resize(int argc, char **argv)
             break;
         }
     }
-    if (optind + 1 >= argc) {
+    if (optind >= argc) {
         help();
     }
     filename = argv[optind++];
-    size = argv[optind++];
 
     /* Choose grow, shrink, or absolute resize mode */
     switch (size[0]) {
index ef60730e4794fad73dbff76009ec74c4ddee9284..489df10c46847e715d78d60c4aac496e8e1eef1b 100644 (file)
@@ -937,8 +937,8 @@ a lot of bandwidth at the expense of quality.
 Disable adaptive encodings. Adaptive encodings are enabled by default.
 An adaptive encoding will try to detect frequently updated screen regions,
 and send updates in these regions using a lossy encoding (like JPEG).
-This can be really helpfull to save bandwidth when playing videos. Disabling
-adaptive encodings allow to restore the original static behavior of encodings
+This can be really helpful to save bandwidth when playing videos. Disabling
+adaptive encodings allows to restore the original static behavior of encodings
 like Tight.
 
 @end table
@@ -1152,7 +1152,7 @@ Assign symbolic name for use in monitor commands.
 @item net=@var{addr}[/@var{mask}]
 Set IP network address the guest will see. Optionally specify the netmask,
 either in the form a.b.c.d or as number of valid top-most bits. Default is
-10.0.2.0/8.
+10.0.2.0/24.
 
 @item host=@var{addr}
 Specify the guest-visible address of the host. Default is the 2nd IP in the
@@ -1168,7 +1168,7 @@ Specifies the client hostname reported by the builtin DHCP server.
 
 @item dhcpstart=@var{addr}
 Specify the first of the 16 IPs the built-in DHCP server can assign. Default
-is the 16th to 31st IP in the guest network, i.e. x.x.x.16 to x.x.x.31.
+is the 15th to 31st IP in the guest network, i.e. x.x.x.15 to x.x.x.31.
 
 @item dns=@var{addr}
 Specify the guest-visible address of the virtual nameserver. The address must
index 1a07e5e264a98a16791b79244ce0afda48461b85..ed2753d1b7b1f653af0ca20080d5c6ec1f49cb52 100644 (file)
@@ -26,6 +26,9 @@
 #ifndef QEMU_OS_WIN32_H
 #define QEMU_OS_WIN32_H
 
+#include <windows.h>
+#include <winsock2.h>
+
 /* Polling handling */
 
 /* return TRUE if no sleep should be done afterwards */
diff --git a/qemu-progress.c b/qemu-progress.c
new file mode 100644 (file)
index 0000000..a4894c0
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * QEMU progress printing utility functions
+ *
+ * Copyright (C) 2011 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "osdep.h"
+#include "sysemu.h"
+#include <stdio.h>
+#include <signal.h>
+
+struct progress_state {
+    float current;
+    float last_print;
+    float min_skip;
+    void (*print)(void);
+    void (*end)(void);
+};
+
+static struct progress_state state;
+static volatile sig_atomic_t print_pending;
+
+/*
+ * Simple progress print function.
+ * @percent relative percent of current operation
+ * @max percent of total operation
+ */
+static void progress_simple_print(void)
+{
+    printf("    (%3.2f/100%%)\r", state.current);
+    fflush(stdout);
+}
+
+static void progress_simple_end(void)
+{
+    printf("\n");
+}
+
+static void progress_simple_init(void)
+{
+    state.print = progress_simple_print;
+    state.end = progress_simple_end;
+}
+
+#ifdef CONFIG_POSIX
+static void sigusr_print(int signal)
+{
+    print_pending = 1;
+}
+#endif
+
+static void progress_dummy_print(void)
+{
+    if (print_pending) {
+        fprintf(stderr, "    (%3.2f/100%%)\n", state.current);
+        print_pending = 0;
+    }
+}
+
+static void progress_dummy_end(void)
+{
+}
+
+static void progress_dummy_init(void)
+{
+#ifdef CONFIG_POSIX
+    struct sigaction action;
+
+    memset(&action, 0, sizeof(action));
+    sigfillset(&action.sa_mask);
+    action.sa_handler = sigusr_print;
+    action.sa_flags = 0;
+    sigaction(SIGUSR1, &action, NULL);
+#endif
+
+    state.print = progress_dummy_print;
+    state.end = progress_dummy_end;
+}
+
+void qemu_progress_init(int enabled, float min_skip)
+{
+    state.min_skip = min_skip;
+    if (enabled) {
+        progress_simple_init();
+    } else {
+        progress_dummy_init();
+    }
+}
+
+void qemu_progress_end(void)
+{
+    state.end();
+}
+
+void qemu_progress_print(float percent, int max)
+{
+    float current;
+
+    if (max == 0) {
+        current = percent;
+    } else {
+        current = state.current + percent / 100 * max;
+    }
+    if (current > 100) {
+        current = 100;
+    }
+    state.current = current;
+
+    if (current > (state.last_print + state.min_skip) ||
+        (current == 100) || (current == 0)) {
+        state.last_print = state.current;
+        state.print();
+    }
+}
index c526324998b07047daec34b209707e2f817d3935..eda1850e9c6a02a1ae52af465c78fc31bf7e9573 100644 (file)
@@ -627,24 +627,28 @@ int unix_connect(const char *path)
 int unix_listen_opts(QemuOpts *opts)
 {
     fprintf(stderr, "unix sockets are not available on windows\n");
+    errno = ENOTSUP;
     return -1;
 }
 
 int unix_connect_opts(QemuOpts *opts)
 {
     fprintf(stderr, "unix sockets are not available on windows\n");
+    errno = ENOTSUP;
     return -1;
 }
 
 int unix_listen(const char *path, char *ostr, int olen)
 {
     fprintf(stderr, "unix sockets are not available on windows\n");
+    errno = ENOTSUP;
     return -1;
 }
 
 int unix_connect(const char *path)
 {
     fprintf(stderr, "unix sockets are not available on windows\n");
+    errno = ENOTSUP;
     return -1;
 }
 
index edc7ab68589e9b3875d19a886b4e64191485af27..0a73d50524929f8a7387c6d163e2c4eb2dfe958a 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __QEMU_THREAD_H
 #define __QEMU_THREAD_H 1
 
+#include <inttypes.h>
+
 typedef struct QemuMutex QemuMutex;
 typedef struct QemuCond QemuCond;
 typedef struct QemuThread QemuThread;
index 50f1943afddafeb29c39259ab631c2dd5260ab71..4141b6edbebf54d06f152370f23f2a3953c8241a 100644 (file)
@@ -110,9 +110,12 @@ static int64_t cpu_get_clock(void)
     }
 }
 
+#ifndef CONFIG_IOTHREAD
 static int64_t qemu_icount_delta(void)
 {
-    if (use_icount == 1) {
+    if (!use_icount) {
+        return 5000 * (int64_t) 1000000;
+    } else if (use_icount == 1) {
         /* When not using an adaptive execution frequency
            we tend to get badly out of sync with real time,
            so just delay for a reasonable amount of time.  */
@@ -121,6 +124,7 @@ static int64_t qemu_icount_delta(void)
         return cpu_get_icount() - cpu_get_clock();
     }
 }
+#endif
 
 /* enable cpu_get_ticks() */
 void cpu_enable_ticks(void)
@@ -153,6 +157,8 @@ void cpu_disable_ticks(void)
 struct QEMUClock {
     int type;
     int enabled;
+
+    QEMUTimer *warp_timer;
 };
 
 struct QEMUTimer {
@@ -169,14 +175,23 @@ struct qemu_alarm_timer {
     int (*start)(struct qemu_alarm_timer *t);
     void (*stop)(struct qemu_alarm_timer *t);
     void (*rearm)(struct qemu_alarm_timer *t);
-    void *priv;
-
+#if defined(__linux__)
+    int fd;
+    timer_t timer;
+#elif defined(_WIN32)
+    HANDLE timer;
+#endif
     char expired;
     char pending;
 };
 
 static struct qemu_alarm_timer *alarm_timer;
 
+static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
+{
+    return timer_head && (timer_head->expire_time <= current_time);
+}
+
 int qemu_alarm_pending(void)
 {
     return alarm_timer->pending;
@@ -200,6 +215,10 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
 
 #ifdef _WIN32
 
+static int mm_start_timer(struct qemu_alarm_timer *t);
+static void mm_stop_timer(struct qemu_alarm_timer *t);
+static void mm_rearm_timer(struct qemu_alarm_timer *t);
+
 static int win32_start_timer(struct qemu_alarm_timer *t);
 static void win32_stop_timer(struct qemu_alarm_timer *t);
 static void win32_rearm_timer(struct qemu_alarm_timer *t);
@@ -284,18 +303,18 @@ static struct qemu_alarm_timer alarm_timers[] = {
 #ifndef _WIN32
 #ifdef __linux__
     {"dynticks", dynticks_start_timer,
-     dynticks_stop_timer, dynticks_rearm_timer, NULL},
+     dynticks_stop_timer, dynticks_rearm_timer},
     /* HPET - if available - is preferred */
-    {"hpet", hpet_start_timer, hpet_stop_timer, NULL, NULL},
+    {"hpet", hpet_start_timer, hpet_stop_timer, NULL},
     /* ...otherwise try RTC */
-    {"rtc", rtc_start_timer, rtc_stop_timer, NULL, NULL},
+    {"rtc", rtc_start_timer, rtc_stop_timer, NULL},
 #endif
-    {"unix", unix_start_timer, unix_stop_timer, NULL, NULL},
+    {"unix", unix_start_timer, unix_stop_timer, NULL},
 #else
-    {"dynticks", win32_start_timer,
-     win32_stop_timer, win32_rearm_timer, NULL},
-    {"win32", win32_start_timer,
-     win32_stop_timer, NULL, NULL},
+    {"mmtimer", mm_start_timer, mm_stop_timer, NULL},
+    {"mmtimer2", mm_start_timer, mm_stop_timer, mm_rearm_timer},
+    {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer},
+    {"win32", win32_start_timer, win32_stop_timer, NULL},
 #endif
     {NULL, }
 };
@@ -386,6 +405,90 @@ void qemu_clock_enable(QEMUClock *clock, int enabled)
     clock->enabled = enabled;
 }
 
+static int64_t vm_clock_warp_start;
+
+static void icount_warp_rt(void *opaque)
+{
+    if (vm_clock_warp_start == -1) {
+        return;
+    }
+
+    if (vm_running) {
+        int64_t clock = qemu_get_clock_ns(rt_clock);
+        int64_t warp_delta = clock - vm_clock_warp_start;
+        if (use_icount == 1) {
+            qemu_icount_bias += warp_delta;
+        } else {
+            /*
+             * In adaptive mode, do not let the vm_clock run too
+             * far ahead of real time.
+             */
+            int64_t cur_time = cpu_get_clock();
+            int64_t cur_icount = qemu_get_clock_ns(vm_clock);
+            int64_t delta = cur_time - cur_icount;
+            qemu_icount_bias += MIN(warp_delta, delta);
+        }
+        if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
+                               qemu_get_clock_ns(vm_clock))) {
+            qemu_notify_event();
+        }
+    }
+    vm_clock_warp_start = -1;
+}
+
+void qemu_clock_warp(QEMUClock *clock)
+{
+    int64_t deadline;
+
+    if (!clock->warp_timer) {
+        return;
+    }
+
+    /*
+     * There are too many global variables to make the "warp" behavior
+     * applicable to other clocks.  But a clock argument removes the
+     * need for if statements all over the place.
+     */
+    assert(clock == vm_clock);
+
+    /*
+     * If the CPUs have been sleeping, advance the vm_clock timer now.  This
+     * ensures that the deadline for the timer is computed correctly below.
+     * This also makes sure that the insn counter is synchronized before the
+     * CPU starts running, in case the CPU is woken by an event other than
+     * the earliest vm_clock timer.
+     */
+    icount_warp_rt(NULL);
+    if (!all_cpu_threads_idle() || !active_timers[clock->type]) {
+        qemu_del_timer(clock->warp_timer);
+        return;
+    }
+
+    vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
+    deadline = qemu_next_icount_deadline();
+    if (deadline > 0) {
+        /*
+         * Ensure the vm_clock proceeds even when the virtual CPU goes to
+         * sleep.  Otherwise, the CPU might be waiting for a future timer
+         * interrupt to wake it up, but the interrupt never comes because
+         * the vCPU isn't running any insns and thus doesn't advance the
+         * vm_clock.
+         *
+         * An extreme solution for this problem would be to never let VCPUs
+         * sleep in icount mode if there is a pending vm_clock timer; rather
+         * time could just advance to the next vm_clock event.  Instead, we
+         * do stop VCPUs and only advance vm_clock after some "real" time,
+         * (related to the time left until the next event) has passed.  This
+         * rt_clock timer will do this.  This avoids that the warps are too
+         * visible externally---for example, you will not be sending network
+         * packets continously instead of every 100ms.
+         */
+        qemu_mod_timer(clock->warp_timer, vm_clock_warp_start + deadline);
+    } else {
+        qemu_notify_event();
+    }
+}
+
 QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
                           QEMUTimerCB *cb, void *opaque)
 {
@@ -438,10 +541,9 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
     pt = &active_timers[ts->clock->type];
     for(;;) {
         t = *pt;
-        if (!t)
-            break;
-        if (t->expire_time > expire_time)
+        if (!qemu_timer_expired_ns(t, expire_time)) {
             break;
+        }
         pt = &t->next;
     }
     ts->expire_time = expire_time;
@@ -454,8 +556,10 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
             qemu_rearm_alarm_timer(alarm_timer);
         }
         /* Interrupt execution to force deadline recalculation.  */
-        if (use_icount)
+        qemu_clock_warp(ts->clock);
+        if (use_icount) {
             qemu_notify_event();
+        }
     }
 }
 
@@ -478,9 +582,7 @@ int qemu_timer_pending(QEMUTimer *ts)
 
 int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
 {
-    if (!timer_head)
-        return 0;
-    return (timer_head->expire_time <= current_time * timer_head->scale);
+    return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
 }
 
 static void qemu_run_timers(QEMUClock *clock)
@@ -495,8 +597,9 @@ static void qemu_run_timers(QEMUClock *clock)
     ptimer_head = &active_timers[clock->type];
     for(;;) {
         ts = *ptimer_head;
-        if (!ts || ts->expire_time > current_time)
+        if (!qemu_timer_expired_ns(ts, current_time)) {
             break;
+        }
         /* remove timer from the list before calling the callback */
         *ptimer_head = ts->next;
         ts->next = NULL;
@@ -576,6 +679,10 @@ void configure_icount(const char *option)
     if (!option)
         return;
 
+#ifdef CONFIG_IOTHREAD
+    vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
+#endif
+
     if (strcmp(option, "auto") != 0) {
         icount_time_shift = strtol(option, NULL, 0);
         use_icount = 1;
@@ -669,21 +776,16 @@ static void host_alarm_handler(int host_signum)
     }
 }
 
-int64_t qemu_next_deadline(void)
+int64_t qemu_next_icount_deadline(void)
 {
     /* To avoid problems with overflow limit this to 2^32.  */
     int64_t delta = INT32_MAX;
 
+    assert(use_icount);
     if (active_timers[QEMU_CLOCK_VIRTUAL]) {
         delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
                      qemu_get_clock_ns(vm_clock);
     }
-    if (active_timers[QEMU_CLOCK_HOST]) {
-        int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
-                 qemu_get_clock_ns(host_clock);
-        if (hdelta < delta)
-            delta = hdelta;
-    }
 
     if (delta < 0)
         delta = 0;
@@ -770,7 +872,7 @@ static int hpet_start_timer(struct qemu_alarm_timer *t)
         goto fail;
 
     enable_sigio_timer(fd);
-    t->priv = (void *)(long)fd;
+    t->fd = fd;
 
     return 0;
 fail:
@@ -780,7 +882,7 @@ fail:
 
 static void hpet_stop_timer(struct qemu_alarm_timer *t)
 {
-    int fd = (long)t->priv;
+    int fd = t->fd;
 
     close(fd);
 }
@@ -809,14 +911,14 @@ static int rtc_start_timer(struct qemu_alarm_timer *t)
 
     enable_sigio_timer(rtc_fd);
 
-    t->priv = (void *)(long)rtc_fd;
+    t->fd = rtc_fd;
 
     return 0;
 }
 
 static void rtc_stop_timer(struct qemu_alarm_timer *t)
 {
-    int rtc_fd = (long)t->priv;
+    int rtc_fd = t->fd;
 
     close(rtc_fd);
 }
@@ -851,21 +953,21 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t)
         return -1;
     }
 
-    t->priv = (void *)(long)host_timer;
+    t->timer = host_timer;
 
     return 0;
 }
 
 static void dynticks_stop_timer(struct qemu_alarm_timer *t)
 {
-    timer_t host_timer = (timer_t)(long)t->priv;
+    timer_t host_timer = t->timer;
 
     timer_delete(host_timer);
 }
 
 static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
 {
-    timer_t host_timer = (timer_t)(long)t->priv;
+    timer_t host_timer = t->timer;
     struct itimerspec timeout;
     int64_t nearest_delta_ns = INT64_MAX;
     int64_t current_ns;
@@ -944,6 +1046,96 @@ static void unix_stop_timer(struct qemu_alarm_timer *t)
 
 #ifdef _WIN32
 
+static MMRESULT mm_timer;
+static unsigned mm_period;
+
+static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg,
+                                      DWORD_PTR dwUser, DWORD_PTR dw1,
+                                      DWORD_PTR dw2)
+{
+    struct qemu_alarm_timer *t = alarm_timer;
+    if (!t) {
+        return;
+    }
+    if (alarm_has_dynticks(t) || qemu_next_alarm_deadline() <= 0) {
+        t->expired = alarm_has_dynticks(t);
+        t->pending = 1;
+        qemu_notify_event();
+    }
+}
+
+static int mm_start_timer(struct qemu_alarm_timer *t)
+{
+    TIMECAPS tc;
+    UINT flags;
+
+    memset(&tc, 0, sizeof(tc));
+    timeGetDevCaps(&tc, sizeof(tc));
+
+    mm_period = tc.wPeriodMin;
+    timeBeginPeriod(mm_period);
+
+    flags = TIME_CALLBACK_FUNCTION;
+    if (alarm_has_dynticks(t)) {
+        flags |= TIME_ONESHOT;
+    } else {
+        flags |= TIME_PERIODIC;
+    }
+
+    mm_timer = timeSetEvent(1,                  /* interval (ms) */
+                            mm_period,          /* resolution */
+                            mm_alarm_handler,   /* function */
+                            (DWORD_PTR)t,       /* parameter */
+                            flags);
+
+    if (!mm_timer) {
+        fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
+                GetLastError());
+        timeEndPeriod(mm_period);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void mm_stop_timer(struct qemu_alarm_timer *t)
+{
+    timeKillEvent(mm_timer);
+    timeEndPeriod(mm_period);
+}
+
+static void mm_rearm_timer(struct qemu_alarm_timer *t)
+{
+    int nearest_delta_ms;
+
+    assert(alarm_has_dynticks(t));
+    if (!active_timers[QEMU_CLOCK_REALTIME] &&
+        !active_timers[QEMU_CLOCK_VIRTUAL] &&
+        !active_timers[QEMU_CLOCK_HOST]) {
+        return;
+    }
+
+    timeKillEvent(mm_timer);
+
+    nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
+    if (nearest_delta_ms < 1) {
+        nearest_delta_ms = 1;
+    }
+    mm_timer = timeSetEvent(nearest_delta_ms,
+                            mm_period,
+                            mm_alarm_handler,
+                            (DWORD_PTR)t,
+                            TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
+
+    if (!mm_timer) {
+        fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",
+                GetLastError());
+
+        timeEndPeriod(mm_period);
+        exit(1);
+    }
+}
+
 static int win32_start_timer(struct qemu_alarm_timer *t)
 {
     HANDLE hTimer;
@@ -967,13 +1159,13 @@ static int win32_start_timer(struct qemu_alarm_timer *t)
         return -1;
     }
 
-    t->priv = (PVOID) hTimer;
+    t->timer = hTimer;
     return 0;
 }
 
 static void win32_stop_timer(struct qemu_alarm_timer *t)
 {
-    HANDLE hTimer = t->priv;
+    HANDLE hTimer = t->timer;
 
     if (hTimer) {
         DeleteTimerQueueTimer(NULL, hTimer, NULL);
@@ -982,7 +1174,7 @@ static void win32_stop_timer(struct qemu_alarm_timer *t)
 
 static void win32_rearm_timer(struct qemu_alarm_timer *t)
 {
-    HANDLE hTimer = t->priv;
+    HANDLE hTimer = t->timer;
     int nearest_delta_ms;
     BOOLEAN success;
 
@@ -1055,39 +1247,41 @@ void quit_timers(void)
 
 int qemu_calculate_timeout(void)
 {
+#ifndef CONFIG_IOTHREAD
     int timeout;
-    int64_t add;
-    int64_t delta;
 
-    /* When using icount, making forward progress with qemu_icount when the
-       guest CPU is idle is critical. We only use the static io-thread timeout
-       for non icount runs.  */
-    if (!use_icount || !vm_running) {
-        return 5000;
-    }
-
-    /* Advance virtual time to the next event.  */
-    delta = qemu_icount_delta();
-    if (delta > 0) {
-        /* If virtual time is ahead of real time then just
-           wait for IO.  */
-        timeout = (delta + 999999) / 1000000;
-    } else {
-        /* Wait for either IO to occur or the next
-           timer event.  */
-        add = qemu_next_deadline();
-        /* We advance the timer before checking for IO.
-           Limit the amount we advance so that early IO
-           activity won't get the guest too far ahead.  */
-        if (add > 10000000)
-            add = 10000000;
-        delta += add;
-        qemu_icount += qemu_icount_round (add);
-        timeout = delta / 1000000;
-        if (timeout < 0)
-            timeout = 0;
+    if (!vm_running)
+        timeout = 5000;
+    else {
+     /* XXX: use timeout computed from timers */
+        int64_t add;
+        int64_t delta;
+        /* Advance virtual time to the next event.  */
+       delta = qemu_icount_delta();
+        if (delta > 0) {
+            /* If virtual time is ahead of real time then just
+               wait for IO.  */
+            timeout = (delta + 999999) / 1000000;
+        } else {
+            /* Wait for either IO to occur or the next
+               timer event.  */
+            add = qemu_next_icount_deadline();
+            /* We advance the timer before checking for IO.
+               Limit the amount we advance so that early IO
+               activity won't get the guest too far ahead.  */
+            if (add > 10000000)
+                add = 10000000;
+            delta += add;
+            qemu_icount += qemu_icount_round (add);
+            timeout = delta / 1000000;
+            if (timeout < 0)
+                timeout = 0;
+        }
     }
 
     return timeout;
+#else /* CONFIG_IOTHREAD */
+    return 1000;
+#endif
 }
 
index 75d567578b3c397f6ab6fa9abd7023848ce5b228..06cbe20914900f12bbd5390246af93790b3cd398 100644 (file)
@@ -7,7 +7,6 @@
 
 #ifdef _WIN32
 #include <windows.h>
-#include <mmsystem.h>
 #endif
 
 /* timers */
@@ -39,6 +38,7 @@ extern QEMUClock *host_clock;
 
 int64_t qemu_get_clock_ns(QEMUClock *clock);
 void qemu_clock_enable(QEMUClock *clock, int enabled);
+void qemu_clock_warp(QEMUClock *clock);
 
 QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
                           QEMUTimerCB *cb, void *opaque);
@@ -50,7 +50,7 @@ int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
 
 void qemu_run_all_timers(void);
 int qemu_alarm_pending(void);
-int64_t qemu_next_deadline(void);
+int64_t qemu_next_icount_deadline(void);
 void configure_alarms(char const *opt);
 void configure_icount(const char *option);
 int qemu_calculate_timeout(void);
@@ -58,6 +58,10 @@ void init_clocks(void);
 int init_timer_alarm(void);
 void quit_timers(void);
 
+int64_t cpu_get_ticks(void);
+void cpu_enable_ticks(void);
+void cpu_disable_ticks(void);
+
 static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb,
                                            void *opaque)
 {
@@ -139,8 +143,6 @@ uint64_t ptimer_get_count(ptimer_state *s);
 void ptimer_set_count(ptimer_state *s, uint64_t count);
 void ptimer_run(ptimer_state *s, int oneshot);
 void ptimer_stop(ptimer_state *s);
-void qemu_put_ptimer(QEMUFile *f, ptimer_state *s);
-void qemu_get_ptimer(QEMUFile *f, ptimer_state *s);
 
 /* icount */
 int64_t qemu_icount_round(int64_t count);
index d45840de288e765f15dba4f37c272f990a3b661e..f4a6ad081c5e5d0cfc9aa90fa93f04c9a3846448 100644 (file)
@@ -15,7 +15,6 @@
 #include "monitor.h"
 #include "qemu-timer.h"
 #include "qemu-log.h"
-#include "sysemu.h"
 
 #include <sys/time.h>
 
diff --git a/roms/SLOF b/roms/SLOF
new file mode 160000 (submodule)
index 0000000..d1d6b53
--- /dev/null
+++ b/roms/SLOF
@@ -0,0 +1 @@
+Subproject commit d1d6b53b713a2b7c2c25685268fa932d28a4b4c0
diff --git a/roms/ipxe b/roms/ipxe
new file mode 160000 (submodule)
index 0000000..7aee315
--- /dev/null
+++ b/roms/ipxe
@@ -0,0 +1 @@
+Subproject commit 7aee315f61aaf1be6d2fff26339f28a1137231a5
index 03fce62975067a963c56b0a554586b8f61e2c887..f4ff1a1db443588a6e94c756f4d193253c4761fe 100644 (file)
--- a/savevm.c
+++ b/savevm.c
@@ -82,6 +82,7 @@
 #include "migration.h"
 #include "qemu_socket.h"
 #include "qemu-queue.h"
+#include "cpus.h"
 
 #define SELF_ANNOUNCE_ROUNDS 5
 
@@ -1007,7 +1008,7 @@ const VMStateInfo vmstate_info_buffer = {
 };
 
 /* unused buffers: space that was used for some fields that are
-   not usefull anymore */
+   not useful anymore */
 
 static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
 {
diff --git a/scripts/refresh-pxe-roms.sh b/scripts/refresh-pxe-roms.sh
new file mode 100755 (executable)
index 0000000..14d5860
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+# PXE ROM build script
+#
+# 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 (C) 2011 Red Hat, Inc.
+#   Authors: Alex Williamson <alex.williamson@redhat.com>
+#
+# Usage: Run from root of qemu tree
+# ./scripts/refresh-pxe-roms.sh
+
+QEMU_DIR=$PWD
+ROM_DIR="pc-bios"
+BUILD_DIR="roms/ipxe"
+LOCAL_CONFIG="src/config/local/general.h"
+
+function cleanup ()
+{
+    if [ -n "$SAVED_CONFIG" ]; then
+        cp "$SAVED_CONFIG" "$BUILD_DIR"/"$LOCAL_CONFIG"
+        rm "$SAVED_CONFIG"
+    fi
+    cd "$QEMU_DIR"
+}
+
+function make_rom ()
+{
+    cd "$BUILD_DIR"/src
+
+    BUILD_LOG=$(mktemp)
+
+    echo Building "$2"...
+    make bin/"$1".rom > "$BUILD_LOG" 2>&1
+    if [ $? -ne 0 ]; then
+        echo Build failed
+        tail --lines=100 "$BUILD_LOG"
+        rm "$BUILD_LOG"
+        cleanup
+        exit 1
+    fi
+    rm "$BUILD_LOG"
+
+    cp bin/"$1".rom "$QEMU_DIR"/"$ROM_DIR"/"$2"
+
+    cd "$QEMU_DIR"
+}
+
+if [ ! -d "$QEMU_DIR"/"$ROM_DIR" ]; then
+    echo "error: can't find $ROM_DIR directory," \
+         "run me from the root of the qemu tree"
+    exit 1
+fi
+
+if [ ! -d "$BUILD_DIR"/src ]; then
+    echo "error: $BUILD_DIR not populated, try:"
+    echo "  git submodule init $BUILD_DIR"
+    echo "  git submodule update $BUILD_DIR"
+    exit 1
+fi
+
+if [ -e "$BUILD_DIR"/"$LOCAL_CONFIG" ]; then
+    SAVED_CONFIG=$(mktemp)
+    cp "$BUILD_DIR"/"$LOCAL_CONFIG" "$SAVED_CONFIG"
+fi
+
+echo "#undef BANNER_TIMEOUT" > "$BUILD_DIR"/"$LOCAL_CONFIG"
+echo "#define BANNER_TIMEOUT 0" >> "$BUILD_DIR"/"$LOCAL_CONFIG"
+
+IPXE_VERSION=$(cd "$BUILD_DIR" && git describe --tags)
+if [ -z "$IPXE_VERSION" ]; then
+    echo "error: unable to retrieve git version"
+    cleanup
+    exit 1
+fi
+
+echo "#undef PRODUCT_NAME" >> "$BUILD_DIR"/"$LOCAL_CONFIG"
+echo "#define PRODUCT_NAME \"iPXE $IPXE_VERSION\"" >> "$BUILD_DIR"/"$LOCAL_CONFIG"
+
+make_rom 8086100e pxe-e1000.rom
+make_rom 80861209 pxe-eepro100.rom
+make_rom 10500940 pxe-ne2k_pci.rom
+make_rom 10222000 pxe-pcnet.rom
+make_rom 10ec8139 pxe-rtl8139.rom
+make_rom 1af41000 pxe-virtio.rom
+
+echo done
+cleanup
index 412f6958632b027efb46cefc64c24f98169cfa26..2155a57df2a02d3ec58321c544cf658245f25dae 100755 (executable)
@@ -51,7 +51,7 @@ get_args()
 {
     local args
     args=${1#*\(}
-    args=${args%\)*}
+    args=${args%%\)*}
     echo "$args"
 }
 
@@ -338,6 +338,7 @@ linetoc_ust()
     name=$(get_name "$1")
     args=$(get_args "$1")
     argnames=$(get_argnames "$1", ",")
+    [ -z "$argnames" ] || argnames=", $argnames"
     fmt=$(get_fmt "$1")
 
     cat <<EOF
@@ -345,7 +346,7 @@ DEFINE_TRACE(ust_$name);
 
 static void ust_${name}_probe($args)
 {
-    trace_mark(ust, $name, "$fmt"$argnames);
+    trace_mark(ust, $name, "$fmt"$argnames);
 }
 EOF
 
@@ -488,7 +489,7 @@ EOF
         cat <<EOF
   $arg = \$arg$i;
 EOF
-       i="$((i+1))"
+        i="$((i+1))"
     done
 
     cat <<EOF
@@ -585,7 +586,7 @@ tracetostap()
        exit 1
     fi
     if [ -z "$probeprefix" ]; then
-       probeprefix="qemu.$targettype.$targetarch";
+        probeprefix="qemu.$targettype.$targetarch";
     fi
     echo "/* This file is autogenerated by tracetool, do not edit. */"
     convert stap
index 19dbec491f032a5e2eb9144241d6c34ac21d41cc..08eba6adc0d8ae29e36d115ddb2568186445db8a 100644 (file)
@@ -119,6 +119,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
        char *bptr;
        const char *curarg;
        int c, i, ret;
+       pid_t pid;
 
        DEBUG_CALL("fork_exec");
        DEBUG_ARG("so = %lx", (long)so);
@@ -142,7 +143,8 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
                }
        }
 
-       switch(fork()) {
+       pid = fork();
+       switch(pid) {
         case -1:
                lprint("Error: fork failed: %s\n", strerror(errno));
                close(s);
@@ -206,6 +208,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
                exit(1);
 
         default:
+               qemu_add_child_watch(pid);
                if (do_pty == 2) {
                        close(s);
                        so->s = master;
index 517f337c437cd8899e9a2bcf36c9e2888f982833..fa15a71e148ed1e92fd622ee3e8a0a40143141d4 100644 (file)
@@ -131,6 +131,18 @@ static void spice_chr_close(struct CharDriverState *chr)
     qemu_free(s);
 }
 
+static void spice_chr_guest_open(struct CharDriverState *chr)
+{
+    SpiceCharDriver *s = chr->opaque;
+    vmc_register_interface(s);
+}
+
+static void spice_chr_guest_close(struct CharDriverState *chr)
+{
+    SpiceCharDriver *s = chr->opaque;
+    vmc_unregister_interface(s);
+}
+
 static void print_allowed_subtypes(void)
 {
     const char** psubtype;
@@ -183,6 +195,8 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
     chr->opaque = s;
     chr->chr_write = spice_chr_write;
     chr->chr_close = spice_chr_close;
+    chr->chr_guest_open = spice_chr_guest_open;
+    chr->chr_guest_close = spice_chr_guest_close;
 
     qemu_chr_generic_open(chr);
 
index bbbd0fd79931a94629699338b6b7486fa4f38c4c..b0296a0d467ae554400d2777661fd4f943654d62 100644 (file)
--- a/sysemu.h
+++ b/sysemu.h
@@ -8,22 +8,9 @@
 #include "qemu-timer.h"
 #include "notify.h"
 
-#ifdef _WIN32
-#include <windows.h>
-#include "qemu-os-win32.h"
-#endif
-
-#ifdef CONFIG_POSIX
-#include "qemu-os-posix.h"
-#endif
-
 /* vl.c */
 extern const char *bios_name;
 
-#define QEMU_FILE_TYPE_BIOS   0
-#define QEMU_FILE_TYPE_KEYMAP 1
-char *qemu_find_file(int type, const char *name);
-
 extern int vm_running;
 extern const char *qemu_name;
 extern uint8_t qemu_uuid[];
@@ -50,14 +37,6 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
 void vm_start(void);
 void vm_stop(int reason);
 
-uint64_t ram_bytes_remaining(void);
-uint64_t ram_bytes_transferred(void);
-uint64_t ram_bytes_total(void);
-
-int64_t cpu_get_ticks(void);
-void cpu_enable_ticks(void);
-void cpu_disable_ticks(void);
-
 void qemu_system_reset_request(void);
 void qemu_system_shutdown_request(void);
 void qemu_system_powerdown_request(void);
@@ -81,10 +60,6 @@ int load_vmstate(const char *name);
 void do_delvm(Monitor *mon, const QDict *qdict);
 void do_info_snapshots(Monitor *mon);
 
-void cpu_synchronize_all_states(void);
-void cpu_synchronize_all_post_reset(void);
-void cpu_synchronize_all_post_init(void);
-
 void qemu_announce_self(void);
 
 void main_loop_wait(int nonblocking);
@@ -100,12 +75,6 @@ int qemu_loadvm_state(QEMUFile *f);
 /* SLIRP */
 void do_info_slirp(Monitor *mon);
 
-/* OS specific functions */
-void os_setup_early_signal_handling(void);
-char *os_find_datadir(const char *argv0);
-void os_parse_cmd_args(int index, const char *optarg);
-void os_pidfile_error(void);
-
 typedef enum DisplayType
 {
     DT_DEFAULT,
@@ -116,7 +85,6 @@ typedef enum DisplayType
 } DisplayType;
 
 extern int autostart;
-extern int incoming_expected;
 extern int bios_size;
 
 typedef enum {
@@ -191,8 +159,6 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 
 extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 
-#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
-
 void do_usb_add(Monitor *mon, const QDict *qdict);
 void do_usb_del(Monitor *mon, const QDict *qdict);
 void usb_info(Monitor *mon);
index 6c2ae2061f0370d8d1e23650b8211375e84ed5c3..4ccb10b0f42d329fe398127279521ea865a8007d 100644 (file)
@@ -904,10 +904,11 @@ uint64_t helper_cmptun (uint64_t a, uint64_t b)
     fa = t_to_float64(a);
     fb = t_to_float64(b);
 
-    if (float64_is_quiet_nan(fa) || float64_is_quiet_nan(fb))
+    if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
         return 0x4000000000000000ULL;
-    else
+    } else {
         return 0;
+    }
 }
 
 uint64_t helper_cmpteq(uint64_t a, uint64_t b)
@@ -917,7 +918,7 @@ uint64_t helper_cmpteq(uint64_t a, uint64_t b)
     fa = t_to_float64(a);
     fb = t_to_float64(b);
 
-    if (float64_eq(fa, fb, &FP_STATUS))
+    if (float64_eq_quiet(fa, fb, &FP_STATUS))
         return 0x4000000000000000ULL;
     else
         return 0;
@@ -956,7 +957,7 @@ uint64_t helper_cmpgeq(uint64_t a, uint64_t b)
     fa = g_to_float64(a);
     fb = g_to_float64(b);
 
-    if (float64_eq(fa, fb, &FP_STATUS))
+    if (float64_eq_quiet(fa, fb, &FP_STATUS))
         return 0x4000000000000000ULL;
     else
         return 0;
@@ -1373,7 +1374,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         /* Exception index and error code are already set */
index 3a1c625f73fc84c617e61ddbd5b7e701822e294e..456ba51ac6a88eb66ccf3396fd45bbd177c91b3a 100644 (file)
@@ -398,7 +398,7 @@ static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
     } else if (use_goto_tb(ctx, dest)) {
         tcg_gen_goto_tb(0);
         tcg_gen_movi_i64(cpu_pc, dest);
-        tcg_gen_exit_tb((long)ctx->tb);
+        tcg_gen_exit_tb((tcg_target_long)ctx->tb);
         return EXIT_GOTO_TB;
     } else {
         tcg_gen_movi_i64(cpu_pc, dest);
@@ -417,12 +417,12 @@ static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond,
 
         tcg_gen_goto_tb(0);
         tcg_gen_movi_i64(cpu_pc, ctx->pc);
-        tcg_gen_exit_tb((long)ctx->tb);
+        tcg_gen_exit_tb((tcg_target_long)ctx->tb);
 
         gen_set_label(lab_true);
         tcg_gen_goto_tb(1);
         tcg_gen_movi_i64(cpu_pc, dest);
-        tcg_gen_exit_tb((long)ctx->tb + 1);
+        tcg_gen_exit_tb((tcg_target_long)ctx->tb + 1);
 
         return EXIT_GOTO_TB;
     } else {
@@ -3367,8 +3367,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
     return env;
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->pc = gen_opc_pc[pc_pos];
 }
index 1ae7982c7f13cc2ac12d53b9f9f10ccf3d18f78d..d5af64465fd8a0c143b8602eebab61522e773928 100644 (file)
@@ -360,7 +360,10 @@ enum arm_features {
     ARM_FEATURE_M, /* Microcontroller profile.  */
     ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
     ARM_FEATURE_THUMB2EE,
-    ARM_FEATURE_V7MP    /* v7 Multiprocessing Extensions */
+    ARM_FEATURE_V7MP,    /* v7 Multiprocessing Extensions */
+    ARM_FEATURE_V4T,
+    ARM_FEATURE_V5,
+    ARM_FEATURE_STRONGARM,
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -391,6 +394,8 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define ARM_CPUID_ARM946      0x41059461
 #define ARM_CPUID_TI915T      0x54029152
 #define ARM_CPUID_TI925T      0x54029252
+#define ARM_CPUID_SA1100      0x4401A11B
+#define ARM_CPUID_SA1110      0x6901B119
 #define ARM_CPUID_PXA250      0x69052100
 #define ARM_CPUID_PXA255      0x69052d00
 #define ARM_CPUID_PXA260      0x69052903
index 78f3d3920359060a989c0abcb37ed46e8c170703..62ae72ec27b1096cc21ce1b7375666125cabc8b0 100644 (file)
@@ -5,7 +5,7 @@
 #include "cpu.h"
 #include "exec-all.h"
 #include "gdbstub.h"
-#include "helpers.h"
+#include "helper.h"
 #include "qemu-common.h"
 #include "host-utils.h"
 #if !defined(CONFIG_USER_ONLY)
@@ -48,17 +48,23 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     env->cp15.c0_cpuid = id;
     switch (id) {
     case ARM_CPUID_ARM926:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_VFP);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_MPU);
         env->cp15.c0_cachetype = 0x0f004006;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
@@ -67,6 +73,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_ARM1136_R2:
     case ARM_CPUID_ARM1136:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_AUXCR);
@@ -79,6 +87,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM11MPCORE:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_VFP);
@@ -91,6 +101,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
@@ -113,6 +125,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA9:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
@@ -140,6 +154,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXM3:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_V7);
@@ -147,6 +163,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_DIV);
         break;
     case ARM_CPUID_ANY: /* For userspace emulation.  */
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
@@ -161,6 +179,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
+        set_feature(env, ARM_FEATURE_V4T);
         set_feature(env, ARM_FEATURE_OMAPCP);
         env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring.  */
         env->cp15.c0_cachetype = 0x5109149;
@@ -173,6 +192,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA260:
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->cp15.c0_cachetype = 0xd172172;
@@ -184,6 +205,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_B1:
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         set_feature(env, ARM_FEATURE_IWMMXT);
@@ -191,6 +214,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
         break;
+    case ARM_CPUID_SA1100:
+    case ARM_CPUID_SA1110:
+        set_feature(env, ARM_FEATURE_STRONGARM);
+        env->cp15.c1_sys = 0x00000070;
+        break;
     default:
         cpu_abort(env, "Bad CPU ID: %x\n", id);
         break;
@@ -246,6 +274,10 @@ void cpu_reset(CPUARMState *env)
     set_flush_to_zero(1, &env->vfp.standard_fp_status);
     set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
     set_default_nan_mode(1, &env->vfp.standard_fp_status);
+    set_float_detect_tininess(float_tininess_before_rounding,
+                              &env->vfp.fp_status);
+    set_float_detect_tininess(float_tininess_before_rounding,
+                              &env->vfp.standard_fp_status);
     tlb_flush(env, 1);
 }
 
@@ -351,6 +383,8 @@ static const struct arm_cpu_t arm_cpu_names[] = {
     { ARM_CPUID_CORTEXA9, "cortex-a9"},
     { ARM_CPUID_TI925T, "ti925t" },
     { ARM_CPUID_PXA250, "pxa250" },
+    { ARM_CPUID_SA1100,    "sa1100" },
+    { ARM_CPUID_SA1110,    "sa1110" },
     { ARM_CPUID_PXA255, "pxa255" },
     { ARM_CPUID_PXA260, "pxa260" },
     { ARM_CPUID_PXA261, "pxa261" },
@@ -856,7 +890,11 @@ void do_interrupt(CPUARMState *env)
     /* Switch to the new mode, and to the correct instruction set.  */
     env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
     env->uncached_cpsr |= mask;
-    env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0;
+    /* this is a lie, as the was no c1_sys on V4T/V5, but who cares
+     * and we should just guard the thumb mode on V4 */
+    if (arm_feature(env, ARM_FEATURE_V4T)) {
+        env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0;
+    }
     env->regs[14] = env->regs[15] + offset;
     env->regs[15] = addr;
     env->interrupt_request |= CPU_INTERRUPT_EXITTB;
@@ -1347,7 +1385,7 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
             /* This may enable/disable the MMU, so do a TLB flush.  */
             tlb_flush(env, 1);
             break;
-        case 1: /* Auxiliary cotrol register.  */
+        case 1: /* Auxiliary control register.  */
             if (arm_feature(env, ARM_FEATURE_XSCALE)) {
                 env->cp15.c1_xscaleauxcr = val;
                 break;
@@ -1522,6 +1560,8 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
     case 9:
         if (arm_feature(env, ARM_FEATURE_OMAPCP))
             break;
+        if (arm_feature(env, ARM_FEATURE_STRONGARM))
+            break; /* Ignore ReadBuffer access */
         switch (crm) {
         case 0: /* Cache lockdown.  */
            switch (op1) {
@@ -2486,135 +2526,98 @@ DO_VFP_cmp(s, float32)
 DO_VFP_cmp(d, float64)
 #undef DO_VFP_cmp
 
-/* Helper routines to perform bitwise copies between float and int.  */
-static inline float32 vfp_itos(uint32_t i)
-{
-    union {
-        uint32_t i;
-        float32 s;
-    } v;
-
-    v.i = i;
-    return v.s;
-}
-
-static inline uint32_t vfp_stoi(float32 s)
-{
-    union {
-        uint32_t i;
-        float32 s;
-    } v;
-
-    v.s = s;
-    return v.i;
-}
-
-static inline float64 vfp_itod(uint64_t i)
-{
-    union {
-        uint64_t i;
-        float64 d;
-    } v;
-
-    v.i = i;
-    return v.d;
-}
-
-static inline uint64_t vfp_dtoi(float64 d)
-{
-    union {
-        uint64_t i;
-        float64 d;
-    } v;
-
-    v.d = d;
-    return v.i;
-}
-
 /* Integer to float conversion.  */
-float32 VFP_HELPER(uito, s)(float32 x, CPUState *env)
+float32 VFP_HELPER(uito, s)(uint32_t x, CPUState *env)
 {
-    return uint32_to_float32(vfp_stoi(x), &env->vfp.fp_status);
+    return uint32_to_float32(x, &env->vfp.fp_status);
 }
 
-float64 VFP_HELPER(uito, d)(float32 x, CPUState *env)
+float64 VFP_HELPER(uito, d)(uint32_t x, CPUState *env)
 {
-    return uint32_to_float64(vfp_stoi(x), &env->vfp.fp_status);
+    return uint32_to_float64(x, &env->vfp.fp_status);
 }
 
-float32 VFP_HELPER(sito, s)(float32 x, CPUState *env)
+float32 VFP_HELPER(sito, s)(uint32_t x, CPUState *env)
 {
-    return int32_to_float32(vfp_stoi(x), &env->vfp.fp_status);
+    return int32_to_float32(x, &env->vfp.fp_status);
 }
 
-float64 VFP_HELPER(sito, d)(float32 x, CPUState *env)
+float64 VFP_HELPER(sito, d)(uint32_t x, CPUState *env)
 {
-    return int32_to_float64(vfp_stoi(x), &env->vfp.fp_status);
+    return int32_to_float64(x, &env->vfp.fp_status);
 }
 
 /* Float to integer conversion.  */
-float32 VFP_HELPER(toui, s)(float32 x, CPUState *env)
+uint32_t VFP_HELPER(toui, s)(float32 x, CPUState *env)
 {
     if (float32_is_any_nan(x)) {
-        return float32_zero;
+        float_raise(float_flag_invalid, &env->vfp.fp_status);
+        return 0;
     }
-    return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status));
+    return float32_to_uint32(x, &env->vfp.fp_status);
 }
 
-float32 VFP_HELPER(toui, d)(float64 x, CPUState *env)
+uint32_t VFP_HELPER(toui, d)(float64 x, CPUState *env)
 {
     if (float64_is_any_nan(x)) {
-        return float32_zero;
+        float_raise(float_flag_invalid, &env->vfp.fp_status);
+        return 0;
     }
-    return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status));
+    return float64_to_uint32(x, &env->vfp.fp_status);
 }
 
-float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env)
+uint32_t VFP_HELPER(tosi, s)(float32 x, CPUState *env)
 {
     if (float32_is_any_nan(x)) {
-        return float32_zero;
+        float_raise(float_flag_invalid, &env->vfp.fp_status);
+        return 0;
     }
-    return vfp_itos(float32_to_int32(x, &env->vfp.fp_status));
+    return float32_to_int32(x, &env->vfp.fp_status);
 }
 
-float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env)
+uint32_t VFP_HELPER(tosi, d)(float64 x, CPUState *env)
 {
     if (float64_is_any_nan(x)) {
-        return float32_zero;
+        float_raise(float_flag_invalid, &env->vfp.fp_status);
+        return 0;
     }
-    return vfp_itos(float64_to_int32(x, &env->vfp.fp_status));
+    return float64_to_int32(x, &env->vfp.fp_status);
 }
 
-float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env)
+uint32_t VFP_HELPER(touiz, s)(float32 x, CPUState *env)
 {
     if (float32_is_any_nan(x)) {
-        return float32_zero;
+        float_raise(float_flag_invalid, &env->vfp.fp_status);
+        return 0;
     }
-    return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status));
+    return float32_to_uint32_round_to_zero(x, &env->vfp.fp_status);
 }
 
-float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env)
+uint32_t VFP_HELPER(touiz, d)(float64 x, CPUState *env)
 {
     if (float64_is_any_nan(x)) {
-        return float32_zero;
+        float_raise(float_flag_invalid, &env->vfp.fp_status);
+        return 0;
     }
-    return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status));
+    return float64_to_uint32_round_to_zero(x, &env->vfp.fp_status);
 }
 
-float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
+uint32_t VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
 {
     if (float32_is_any_nan(x)) {
-        return float32_zero;
+        float_raise(float_flag_invalid, &env->vfp.fp_status);
+        return 0;
     }
-    return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status));
+    return float32_to_int32_round_to_zero(x, &env->vfp.fp_status);
 }
 
-float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
+uint32_t VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
 {
     if (float64_is_any_nan(x)) {
-        return float32_zero;
+        float_raise(float_flag_invalid, &env->vfp.fp_status);
+        return 0;
     }
-    return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status));
+    return float64_to_int32_round_to_zero(x, &env->vfp.fp_status);
 }
 
 /* floating point conversion */
@@ -2637,33 +2640,34 @@ float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env)
 }
 
 /* VFP3 fixed point conversion.  */
-#define VFP_CONV_FIX(name, p, ftype, itype, sign) \
-ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \
+#define VFP_CONV_FIX(name, p, fsz, itype, sign) \
+float##fsz VFP_HELPER(name##to, p)(uint##fsz##_t  x, uint32_t shift, \
+                                   CPUState *env) \
 { \
-    ftype tmp; \
-    tmp = sign##int32_to_##ftype ((itype##_t)vfp_##p##toi(x), \
-                                  &env->vfp.fp_status); \
-    return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
+    float##fsz tmp; \
+    tmp = sign##int32_to_##float##fsz ((itype##_t)x, &env->vfp.fp_status); \
+    return float##fsz##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
 } \
-ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
+uint##fsz##_t VFP_HELPER(to##name, p)(float##fsz x, uint32_t shift, \
+                                      CPUState *env) \
 { \
-    ftype tmp; \
-    if (ftype##_is_any_nan(x)) { \
-        return ftype##_zero; \
+    float##fsz tmp; \
+    if (float##fsz##_is_any_nan(x)) { \
+        float_raise(float_flag_invalid, &env->vfp.fp_status); \
+        return 0; \
     } \
-    tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \
-    return vfp_ito##p(ftype##_to_##itype##_round_to_zero(tmp, \
-        &env->vfp.fp_status)); \
-}
-
-VFP_CONV_FIX(sh, d, float64, int16, )
-VFP_CONV_FIX(sl, d, float64, int32, )
-VFP_CONV_FIX(uh, d, float64, uint16, u)
-VFP_CONV_FIX(ul, d, float64, uint32, u)
-VFP_CONV_FIX(sh, s, float32, int16, )
-VFP_CONV_FIX(sl, s, float32, int32, )
-VFP_CONV_FIX(uh, s, float32, uint16, u)
-VFP_CONV_FIX(ul, s, float32, uint32, u)
+    tmp = float##fsz##_scalbn(x, shift, &env->vfp.fp_status); \
+    return float##fsz##_to_##itype##_round_to_zero(tmp, &env->vfp.fp_status); \
+}
+
+VFP_CONV_FIX(sh, d, 64, int16, )
+VFP_CONV_FIX(sl, d, 64, int32, )
+VFP_CONV_FIX(uh, d, 64, uint16, u)
+VFP_CONV_FIX(ul, d, 64, uint32, u)
+VFP_CONV_FIX(sh, s, 32, int16, )
+VFP_CONV_FIX(sl, s, 32, int32, )
+VFP_CONV_FIX(uh, s, 32, uint16, u)
+VFP_CONV_FIX(ul, s, 32, uint32, u)
 #undef VFP_CONV_FIX
 
 /* Half precision conversions.  */
diff --git a/target-arm/helper.h b/target-arm/helper.h
new file mode 100644 (file)
index 0000000..ae701e8
--- /dev/null
@@ -0,0 +1,475 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(clz, i32, i32)
+DEF_HELPER_1(sxtb16, i32, i32)
+DEF_HELPER_1(uxtb16, i32, i32)
+
+DEF_HELPER_2(add_setq, i32, i32, i32)
+DEF_HELPER_2(add_saturate, i32, i32, i32)
+DEF_HELPER_2(sub_saturate, i32, i32, i32)
+DEF_HELPER_2(add_usaturate, i32, i32, i32)
+DEF_HELPER_2(sub_usaturate, i32, i32, i32)
+DEF_HELPER_1(double_saturate, i32, s32)
+DEF_HELPER_2(sdiv, s32, s32, s32)
+DEF_HELPER_2(udiv, i32, i32, i32)
+DEF_HELPER_1(rbit, i32, i32)
+DEF_HELPER_1(abs, i32, i32)
+
+#define PAS_OP(pfx)  \
+    DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## sub16, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## add16, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## addsubx, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## subaddx, i32, i32, i32, ptr)
+
+PAS_OP(s)
+PAS_OP(u)
+#undef PAS_OP
+
+#define PAS_OP(pfx)  \
+    DEF_HELPER_2(pfx ## add8, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## sub8, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## sub16, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## add16, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## addsubx, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## subaddx, i32, i32, i32)
+PAS_OP(q)
+PAS_OP(sh)
+PAS_OP(uq)
+PAS_OP(uh)
+#undef PAS_OP
+
+DEF_HELPER_2(ssat, i32, i32, i32)
+DEF_HELPER_2(usat, i32, i32, i32)
+DEF_HELPER_2(ssat16, i32, i32, i32)
+DEF_HELPER_2(usat16, i32, i32, i32)
+
+DEF_HELPER_2(usad8, i32, i32, i32)
+
+DEF_HELPER_1(logicq_cc, i32, i64)
+
+DEF_HELPER_3(sel_flags, i32, i32, i32, i32)
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_0(wfi, void)
+
+DEF_HELPER_2(cpsr_write, void, i32, i32)
+DEF_HELPER_0(cpsr_read, i32)
+
+DEF_HELPER_3(v7m_msr, void, env, i32, i32)
+DEF_HELPER_2(v7m_mrs, i32, env, i32)
+
+DEF_HELPER_3(set_cp15, void, env, i32, i32)
+DEF_HELPER_2(get_cp15, i32, env, i32)
+
+DEF_HELPER_3(set_cp, void, env, i32, i32)
+DEF_HELPER_2(get_cp, i32, env, i32)
+
+DEF_HELPER_2(get_r13_banked, i32, env, i32)
+DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
+
+DEF_HELPER_1(get_user_reg, i32, i32)
+DEF_HELPER_2(set_user_reg, void, i32, i32)
+
+DEF_HELPER_1(vfp_get_fpscr, i32, env)
+DEF_HELPER_2(vfp_set_fpscr, void, env, i32)
+
+DEF_HELPER_3(vfp_adds, f32, f32, f32, env)
+DEF_HELPER_3(vfp_addd, f64, f64, f64, env)
+DEF_HELPER_3(vfp_subs, f32, f32, f32, env)
+DEF_HELPER_3(vfp_subd, f64, f64, f64, env)
+DEF_HELPER_3(vfp_muls, f32, f32, f32, env)
+DEF_HELPER_3(vfp_muld, f64, f64, f64, env)
+DEF_HELPER_3(vfp_divs, f32, f32, f32, env)
+DEF_HELPER_3(vfp_divd, f64, f64, f64, env)
+DEF_HELPER_1(vfp_negs, f32, f32)
+DEF_HELPER_1(vfp_negd, f64, f64)
+DEF_HELPER_1(vfp_abss, f32, f32)
+DEF_HELPER_1(vfp_absd, f64, f64)
+DEF_HELPER_2(vfp_sqrts, f32, f32, env)
+DEF_HELPER_2(vfp_sqrtd, f64, f64, env)
+DEF_HELPER_3(vfp_cmps, void, f32, f32, env)
+DEF_HELPER_3(vfp_cmpd, void, f64, f64, env)
+DEF_HELPER_3(vfp_cmpes, void, f32, f32, env)
+DEF_HELPER_3(vfp_cmped, void, f64, f64, env)
+
+DEF_HELPER_2(vfp_fcvtds, f64, f32, env)
+DEF_HELPER_2(vfp_fcvtsd, f32, f64, env)
+
+DEF_HELPER_2(vfp_uitos, f32, i32, env)
+DEF_HELPER_2(vfp_uitod, f64, i32, env)
+DEF_HELPER_2(vfp_sitos, f32, i32, env)
+DEF_HELPER_2(vfp_sitod, f64, i32, env)
+
+DEF_HELPER_2(vfp_touis, i32, f32, env)
+DEF_HELPER_2(vfp_touid, i32, f64, env)
+DEF_HELPER_2(vfp_touizs, i32, f32, env)
+DEF_HELPER_2(vfp_touizd, i32, f64, env)
+DEF_HELPER_2(vfp_tosis, i32, f32, env)
+DEF_HELPER_2(vfp_tosid, i32, f64, env)
+DEF_HELPER_2(vfp_tosizs, i32, f32, env)
+DEF_HELPER_2(vfp_tosizd, i32, f64, env)
+
+DEF_HELPER_3(vfp_toshs, i32, f32, i32, env)
+DEF_HELPER_3(vfp_tosls, i32, f32, i32, env)
+DEF_HELPER_3(vfp_touhs, i32, f32, i32, env)
+DEF_HELPER_3(vfp_touls, i32, f32, i32, env)
+DEF_HELPER_3(vfp_toshd, i64, f64, i32, env)
+DEF_HELPER_3(vfp_tosld, i64, f64, i32, env)
+DEF_HELPER_3(vfp_touhd, i64, f64, i32, env)
+DEF_HELPER_3(vfp_tould, i64, f64, i32, env)
+DEF_HELPER_3(vfp_shtos, f32, i32, i32, env)
+DEF_HELPER_3(vfp_sltos, f32, i32, i32, env)
+DEF_HELPER_3(vfp_uhtos, f32, i32, i32, env)
+DEF_HELPER_3(vfp_ultos, f32, i32, i32, env)
+DEF_HELPER_3(vfp_shtod, f64, i64, i32, env)
+DEF_HELPER_3(vfp_sltod, f64, i64, i32, env)
+DEF_HELPER_3(vfp_uhtod, f64, i64, i32, env)
+DEF_HELPER_3(vfp_ultod, f64, i64, i32, env)
+
+DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env)
+DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env)
+DEF_HELPER_2(neon_fcvt_f16_to_f32, f32, i32, env)
+DEF_HELPER_2(neon_fcvt_f32_to_f16, i32, f32, env)
+
+DEF_HELPER_3(recps_f32, f32, f32, f32, env)
+DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env)
+DEF_HELPER_2(recpe_f32, f32, f32, env)
+DEF_HELPER_2(rsqrte_f32, f32, f32, env)
+DEF_HELPER_2(recpe_u32, i32, i32, env)
+DEF_HELPER_2(rsqrte_u32, i32, i32, env)
+DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32)
+
+DEF_HELPER_2(add_cc, i32, i32, i32)
+DEF_HELPER_2(adc_cc, i32, i32, i32)
+DEF_HELPER_2(sub_cc, i32, i32, i32)
+DEF_HELPER_2(sbc_cc, i32, i32, i32)
+
+DEF_HELPER_2(shl, i32, i32, i32)
+DEF_HELPER_2(shr, i32, i32, i32)
+DEF_HELPER_2(sar, i32, i32, i32)
+DEF_HELPER_2(shl_cc, i32, i32, i32)
+DEF_HELPER_2(shr_cc, i32, i32, i32)
+DEF_HELPER_2(sar_cc, i32, i32, i32)
+DEF_HELPER_2(ror_cc, i32, i32, i32)
+
+/* neon_helper.c */
+DEF_HELPER_2(neon_qadd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_qadd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_qadd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_qadd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_qadd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_qadd_s32, i32, i32, i32)
+DEF_HELPER_2(neon_qsub_u8, i32, i32, i32)
+DEF_HELPER_2(neon_qsub_s8, i32, i32, i32)
+DEF_HELPER_2(neon_qsub_u16, i32, i32, i32)
+DEF_HELPER_2(neon_qsub_s16, i32, i32, i32)
+DEF_HELPER_2(neon_qsub_u32, i32, i32, i32)
+DEF_HELPER_2(neon_qsub_s32, i32, i32, i32)
+DEF_HELPER_2(neon_qadd_u64, i64, i64, i64)
+DEF_HELPER_2(neon_qadd_s64, i64, i64, i64)
+DEF_HELPER_2(neon_qsub_u64, i64, i64, i64)
+DEF_HELPER_2(neon_qsub_s64, i64, i64, i64)
+
+DEF_HELPER_2(neon_hadd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_s32, s32, s32, s32)
+DEF_HELPER_2(neon_hadd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s32, s32, s32, s32)
+DEF_HELPER_2(neon_rhadd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s8, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_u8, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s16, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_u16, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s32, s32, s32, s32)
+DEF_HELPER_2(neon_hsub_u32, i32, i32, i32)
+
+DEF_HELPER_2(neon_cgt_u8, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s8, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_u16, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s16, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_u32, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s32, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u8, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s8, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u16, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s16, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u32, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s32, i32, i32, i32)
+
+DEF_HELPER_2(neon_min_u8, i32, i32, i32)
+DEF_HELPER_2(neon_min_s8, i32, i32, i32)
+DEF_HELPER_2(neon_min_u16, i32, i32, i32)
+DEF_HELPER_2(neon_min_s16, i32, i32, i32)
+DEF_HELPER_2(neon_min_u32, i32, i32, i32)
+DEF_HELPER_2(neon_min_s32, i32, i32, i32)
+DEF_HELPER_2(neon_max_u8, i32, i32, i32)
+DEF_HELPER_2(neon_max_s8, i32, i32, i32)
+DEF_HELPER_2(neon_max_u16, i32, i32, i32)
+DEF_HELPER_2(neon_max_s16, i32, i32, i32)
+DEF_HELPER_2(neon_max_u32, i32, i32, i32)
+DEF_HELPER_2(neon_max_s32, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_u8, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_s8, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_u16, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_s16, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_u8, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_s8, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_u16, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_s16, i32, i32, i32)
+
+DEF_HELPER_2(neon_abd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_abd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_abd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s32, i32, i32, i32)
+
+DEF_HELPER_2(neon_shl_u8, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s8, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u16, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s16, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u32, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s32, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u64, i64, i64, i64)
+DEF_HELPER_2(neon_shl_s64, i64, i64, i64)
+DEF_HELPER_2(neon_rshl_u8, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s8, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u16, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s16, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u32, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s32, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u64, i64, i64, i64)
+DEF_HELPER_2(neon_rshl_s64, i64, i64, i64)
+DEF_HELPER_2(neon_qshl_u8, i32, i32, i32)
+DEF_HELPER_2(neon_qshl_s8, i32, i32, i32)
+DEF_HELPER_2(neon_qshl_u16, i32, i32, i32)
+DEF_HELPER_2(neon_qshl_s16, i32, i32, i32)
+DEF_HELPER_2(neon_qshl_u32, i32, i32, i32)
+DEF_HELPER_2(neon_qshl_s32, i32, i32, i32)
+DEF_HELPER_2(neon_qshl_u64, i64, i64, i64)
+DEF_HELPER_2(neon_qshl_s64, i64, i64, i64)
+DEF_HELPER_2(neon_qshlu_s8, i32, i32, i32);
+DEF_HELPER_2(neon_qshlu_s16, i32, i32, i32);
+DEF_HELPER_2(neon_qshlu_s32, i32, i32, i32);
+DEF_HELPER_2(neon_qshlu_s64, i64, i64, i64);
+DEF_HELPER_2(neon_qrshl_u8, i32, i32, i32)
+DEF_HELPER_2(neon_qrshl_s8, i32, i32, i32)
+DEF_HELPER_2(neon_qrshl_u16, i32, i32, i32)
+DEF_HELPER_2(neon_qrshl_s16, i32, i32, i32)
+DEF_HELPER_2(neon_qrshl_u32, i32, i32, i32)
+DEF_HELPER_2(neon_qrshl_s32, i32, i32, i32)
+DEF_HELPER_2(neon_qrshl_u64, i64, i64, i64)
+DEF_HELPER_2(neon_qrshl_s64, i64, i64, i64)
+
+DEF_HELPER_2(neon_add_u8, i32, i32, i32)
+DEF_HELPER_2(neon_add_u16, i32, i32, i32)
+DEF_HELPER_2(neon_padd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_padd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_sub_u8, i32, i32, i32)
+DEF_HELPER_2(neon_sub_u16, i32, i32, i32)
+DEF_HELPER_2(neon_mul_u8, i32, i32, i32)
+DEF_HELPER_2(neon_mul_u16, i32, i32, i32)
+DEF_HELPER_2(neon_mul_p8, i32, i32, i32)
+DEF_HELPER_2(neon_mull_p8, i64, i32, i32)
+
+DEF_HELPER_2(neon_tst_u8, i32, i32, i32)
+DEF_HELPER_2(neon_tst_u16, i32, i32, i32)
+DEF_HELPER_2(neon_tst_u32, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u8, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u16, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u32, i32, i32, i32)
+
+DEF_HELPER_1(neon_abs_s8, i32, i32)
+DEF_HELPER_1(neon_abs_s16, i32, i32)
+DEF_HELPER_1(neon_clz_u8, i32, i32)
+DEF_HELPER_1(neon_clz_u16, i32, i32)
+DEF_HELPER_1(neon_cls_s8, i32, i32)
+DEF_HELPER_1(neon_cls_s16, i32, i32)
+DEF_HELPER_1(neon_cls_s32, i32, i32)
+DEF_HELPER_1(neon_cnt_u8, i32, i32)
+
+DEF_HELPER_2(neon_qdmulh_s16, i32, i32, i32)
+DEF_HELPER_2(neon_qrdmulh_s16, i32, i32, i32)
+DEF_HELPER_2(neon_qdmulh_s32, i32, i32, i32)
+DEF_HELPER_2(neon_qrdmulh_s32, i32, i32, i32)
+
+DEF_HELPER_1(neon_narrow_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_u16, i32, i64)
+DEF_HELPER_1(neon_unarrow_sat8, i32, i64)
+DEF_HELPER_1(neon_narrow_sat_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_sat_s8, i32, i64)
+DEF_HELPER_1(neon_unarrow_sat16, i32, i64)
+DEF_HELPER_1(neon_narrow_sat_u16, i32, i64)
+DEF_HELPER_1(neon_narrow_sat_s16, i32, i64)
+DEF_HELPER_1(neon_unarrow_sat32, i32, i64)
+DEF_HELPER_1(neon_narrow_sat_u32, i32, i64)
+DEF_HELPER_1(neon_narrow_sat_s32, i32, i64)
+DEF_HELPER_1(neon_narrow_high_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_high_u16, i32, i64)
+DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_round_high_u16, i32, i64)
+DEF_HELPER_1(neon_widen_u8, i64, i32)
+DEF_HELPER_1(neon_widen_s8, i64, i32)
+DEF_HELPER_1(neon_widen_u16, i64, i32)
+DEF_HELPER_1(neon_widen_s16, i64, i32)
+
+DEF_HELPER_2(neon_addl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_addl_u32, i64, i64, i64)
+DEF_HELPER_2(neon_paddl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_paddl_u32, i64, i64, i64)
+DEF_HELPER_2(neon_subl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_subl_u32, i64, i64, i64)
+DEF_HELPER_2(neon_addl_saturate_s32, i64, i64, i64)
+DEF_HELPER_2(neon_addl_saturate_s64, i64, i64, i64)
+DEF_HELPER_2(neon_abdl_u16, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s16, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_u32, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s32, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_u64, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s64, i64, i32, i32)
+DEF_HELPER_2(neon_mull_u8, i64, i32, i32)
+DEF_HELPER_2(neon_mull_s8, i64, i32, i32)
+DEF_HELPER_2(neon_mull_u16, i64, i32, i32)
+DEF_HELPER_2(neon_mull_s16, i64, i32, i32)
+
+DEF_HELPER_1(neon_negl_u16, i64, i64)
+DEF_HELPER_1(neon_negl_u32, i64, i64)
+DEF_HELPER_1(neon_negl_u64, i64, i64)
+
+DEF_HELPER_1(neon_qabs_s8, i32, i32)
+DEF_HELPER_1(neon_qabs_s16, i32, i32)
+DEF_HELPER_1(neon_qabs_s32, i32, i32)
+DEF_HELPER_1(neon_qneg_s8, i32, i32)
+DEF_HELPER_1(neon_qneg_s16, i32, i32)
+DEF_HELPER_1(neon_qneg_s32, i32, i32)
+
+DEF_HELPER_2(neon_min_f32, i32, i32, i32)
+DEF_HELPER_2(neon_max_f32, i32, i32, i32)
+DEF_HELPER_2(neon_abd_f32, i32, i32, i32)
+DEF_HELPER_2(neon_add_f32, i32, i32, i32)
+DEF_HELPER_2(neon_sub_f32, i32, i32, i32)
+DEF_HELPER_2(neon_mul_f32, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_f32, i32, i32, i32)
+DEF_HELPER_2(neon_cge_f32, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_f32, i32, i32, i32)
+DEF_HELPER_2(neon_acge_f32, i32, i32, i32)
+DEF_HELPER_2(neon_acgt_f32, i32, i32, i32)
+
+/* iwmmxt_helper.c */
+DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64)
+DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64)
+
+#define DEF_IWMMXT_HELPER_SIZE(name) \
+DEF_HELPER_2(iwmmxt_##name##b, i64, i64, i64) \
+DEF_HELPER_2(iwmmxt_##name##w, i64, i64, i64) \
+DEF_HELPER_2(iwmmxt_##name##l, i64, i64, i64) \
+
+DEF_IWMMXT_HELPER_SIZE(unpackl)
+DEF_IWMMXT_HELPER_SIZE(unpackh)
+
+DEF_HELPER_1(iwmmxt_unpacklub, i64, i64)
+DEF_HELPER_1(iwmmxt_unpackluw, i64, i64)
+DEF_HELPER_1(iwmmxt_unpacklul, i64, i64)
+DEF_HELPER_1(iwmmxt_unpackhub, i64, i64)
+DEF_HELPER_1(iwmmxt_unpackhuw, i64, i64)
+DEF_HELPER_1(iwmmxt_unpackhul, i64, i64)
+DEF_HELPER_1(iwmmxt_unpacklsb, i64, i64)
+DEF_HELPER_1(iwmmxt_unpacklsw, i64, i64)
+DEF_HELPER_1(iwmmxt_unpacklsl, i64, i64)
+DEF_HELPER_1(iwmmxt_unpackhsb, i64, i64)
+DEF_HELPER_1(iwmmxt_unpackhsw, i64, i64)
+DEF_HELPER_1(iwmmxt_unpackhsl, i64, i64)
+
+DEF_IWMMXT_HELPER_SIZE(cmpeq)
+DEF_IWMMXT_HELPER_SIZE(cmpgtu)
+DEF_IWMMXT_HELPER_SIZE(cmpgts)
+
+DEF_IWMMXT_HELPER_SIZE(mins)
+DEF_IWMMXT_HELPER_SIZE(minu)
+DEF_IWMMXT_HELPER_SIZE(maxs)
+DEF_IWMMXT_HELPER_SIZE(maxu)
+
+DEF_IWMMXT_HELPER_SIZE(subn)
+DEF_IWMMXT_HELPER_SIZE(addn)
+DEF_IWMMXT_HELPER_SIZE(subu)
+DEF_IWMMXT_HELPER_SIZE(addu)
+DEF_IWMMXT_HELPER_SIZE(subs)
+DEF_IWMMXT_HELPER_SIZE(adds)
+
+DEF_HELPER_2(iwmmxt_avgb0, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_avgb1, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_avgw0, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_avgw1, i64, i64, i64)
+
+DEF_HELPER_2(iwmmxt_msadb, i64, i64, i64)
+
+DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32)
+DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32)
+
+DEF_HELPER_1(iwmmxt_bcstb, i64, i32)
+DEF_HELPER_1(iwmmxt_bcstw, i64, i32)
+DEF_HELPER_1(iwmmxt_bcstl, i64, i32)
+
+DEF_HELPER_1(iwmmxt_addcb, i64, i64)
+DEF_HELPER_1(iwmmxt_addcw, i64, i64)
+DEF_HELPER_1(iwmmxt_addcl, i64, i64)
+
+DEF_HELPER_1(iwmmxt_msbb, i32, i64)
+DEF_HELPER_1(iwmmxt_msbw, i32, i64)
+DEF_HELPER_1(iwmmxt_msbl, i32, i64)
+
+DEF_HELPER_2(iwmmxt_srlw, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_srll, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_srlq, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_sllw, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_slll, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_sllq, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_sraw, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_sral, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_sraq, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_rorw, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_rorl, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_rorq, i64, i64, i32)
+DEF_HELPER_2(iwmmxt_shufh, i64, i64, i32)
+
+DEF_HELPER_2(iwmmxt_packuw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_packul, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_packuq, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_packsw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_packsl, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_packsq, i64, i64, i64)
+
+DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32)
+DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32)
+DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32)
+
+DEF_HELPER_2(set_teecr, void, env, i32)
+
+DEF_HELPER_2(neon_unzip8, void, i32, i32)
+DEF_HELPER_2(neon_unzip16, void, i32, i32)
+DEF_HELPER_2(neon_qunzip8, void, i32, i32)
+DEF_HELPER_2(neon_qunzip16, void, i32, i32)
+DEF_HELPER_2(neon_qunzip32, void, i32, i32)
+DEF_HELPER_2(neon_zip8, void, i32, i32)
+DEF_HELPER_2(neon_zip16, void, i32, i32)
+DEF_HELPER_2(neon_qzip8, void, i32, i32)
+DEF_HELPER_2(neon_qzip16, void, i32, i32)
+DEF_HELPER_2(neon_qzip32, void, i32, i32)
+
+#include "def-helper.h"
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
deleted file mode 100644 (file)
index bd6977c..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-#include "def-helper.h"
-
-DEF_HELPER_1(clz, i32, i32)
-DEF_HELPER_1(sxtb16, i32, i32)
-DEF_HELPER_1(uxtb16, i32, i32)
-
-DEF_HELPER_2(add_setq, i32, i32, i32)
-DEF_HELPER_2(add_saturate, i32, i32, i32)
-DEF_HELPER_2(sub_saturate, i32, i32, i32)
-DEF_HELPER_2(add_usaturate, i32, i32, i32)
-DEF_HELPER_2(sub_usaturate, i32, i32, i32)
-DEF_HELPER_1(double_saturate, i32, s32)
-DEF_HELPER_2(sdiv, s32, s32, s32)
-DEF_HELPER_2(udiv, i32, i32, i32)
-DEF_HELPER_1(rbit, i32, i32)
-DEF_HELPER_1(abs, i32, i32)
-
-#define PAS_OP(pfx)  \
-    DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \
-    DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \
-    DEF_HELPER_3(pfx ## sub16, i32, i32, i32, ptr) \
-    DEF_HELPER_3(pfx ## add16, i32, i32, i32, ptr) \
-    DEF_HELPER_3(pfx ## addsubx, i32, i32, i32, ptr) \
-    DEF_HELPER_3(pfx ## subaddx, i32, i32, i32, ptr)
-
-PAS_OP(s)
-PAS_OP(u)
-#undef PAS_OP
-
-#define PAS_OP(pfx)  \
-    DEF_HELPER_2(pfx ## add8, i32, i32, i32) \
-    DEF_HELPER_2(pfx ## sub8, i32, i32, i32) \
-    DEF_HELPER_2(pfx ## sub16, i32, i32, i32) \
-    DEF_HELPER_2(pfx ## add16, i32, i32, i32) \
-    DEF_HELPER_2(pfx ## addsubx, i32, i32, i32) \
-    DEF_HELPER_2(pfx ## subaddx, i32, i32, i32)
-PAS_OP(q)
-PAS_OP(sh)
-PAS_OP(uq)
-PAS_OP(uh)
-#undef PAS_OP
-
-DEF_HELPER_2(ssat, i32, i32, i32)
-DEF_HELPER_2(usat, i32, i32, i32)
-DEF_HELPER_2(ssat16, i32, i32, i32)
-DEF_HELPER_2(usat16, i32, i32, i32)
-
-DEF_HELPER_2(usad8, i32, i32, i32)
-
-DEF_HELPER_1(logicq_cc, i32, i64)
-
-DEF_HELPER_3(sel_flags, i32, i32, i32, i32)
-DEF_HELPER_1(exception, void, i32)
-DEF_HELPER_0(wfi, void)
-
-DEF_HELPER_2(cpsr_write, void, i32, i32)
-DEF_HELPER_0(cpsr_read, i32)
-
-DEF_HELPER_3(v7m_msr, void, env, i32, i32)
-DEF_HELPER_2(v7m_mrs, i32, env, i32)
-
-DEF_HELPER_3(set_cp15, void, env, i32, i32)
-DEF_HELPER_2(get_cp15, i32, env, i32)
-
-DEF_HELPER_3(set_cp, void, env, i32, i32)
-DEF_HELPER_2(get_cp, i32, env, i32)
-
-DEF_HELPER_2(get_r13_banked, i32, env, i32)
-DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
-
-DEF_HELPER_1(get_user_reg, i32, i32)
-DEF_HELPER_2(set_user_reg, void, i32, i32)
-
-DEF_HELPER_1(vfp_get_fpscr, i32, env)
-DEF_HELPER_2(vfp_set_fpscr, void, env, i32)
-
-DEF_HELPER_3(vfp_adds, f32, f32, f32, env)
-DEF_HELPER_3(vfp_addd, f64, f64, f64, env)
-DEF_HELPER_3(vfp_subs, f32, f32, f32, env)
-DEF_HELPER_3(vfp_subd, f64, f64, f64, env)
-DEF_HELPER_3(vfp_muls, f32, f32, f32, env)
-DEF_HELPER_3(vfp_muld, f64, f64, f64, env)
-DEF_HELPER_3(vfp_divs, f32, f32, f32, env)
-DEF_HELPER_3(vfp_divd, f64, f64, f64, env)
-DEF_HELPER_1(vfp_negs, f32, f32)
-DEF_HELPER_1(vfp_negd, f64, f64)
-DEF_HELPER_1(vfp_abss, f32, f32)
-DEF_HELPER_1(vfp_absd, f64, f64)
-DEF_HELPER_2(vfp_sqrts, f32, f32, env)
-DEF_HELPER_2(vfp_sqrtd, f64, f64, env)
-DEF_HELPER_3(vfp_cmps, void, f32, f32, env)
-DEF_HELPER_3(vfp_cmpd, void, f64, f64, env)
-DEF_HELPER_3(vfp_cmpes, void, f32, f32, env)
-DEF_HELPER_3(vfp_cmped, void, f64, f64, env)
-
-DEF_HELPER_2(vfp_fcvtds, f64, f32, env)
-DEF_HELPER_2(vfp_fcvtsd, f32, f64, env)
-
-DEF_HELPER_2(vfp_uitos, f32, f32, env)
-DEF_HELPER_2(vfp_uitod, f64, f32, env)
-DEF_HELPER_2(vfp_sitos, f32, f32, env)
-DEF_HELPER_2(vfp_sitod, f64, f32, env)
-
-DEF_HELPER_2(vfp_touis, f32, f32, env)
-DEF_HELPER_2(vfp_touid, f32, f64, env)
-DEF_HELPER_2(vfp_touizs, f32, f32, env)
-DEF_HELPER_2(vfp_touizd, f32, f64, env)
-DEF_HELPER_2(vfp_tosis, f32, f32, env)
-DEF_HELPER_2(vfp_tosid, f32, f64, env)
-DEF_HELPER_2(vfp_tosizs, f32, f32, env)
-DEF_HELPER_2(vfp_tosizd, f32, f64, env)
-
-DEF_HELPER_3(vfp_toshs, f32, f32, i32, env)
-DEF_HELPER_3(vfp_tosls, f32, f32, i32, env)
-DEF_HELPER_3(vfp_touhs, f32, f32, i32, env)
-DEF_HELPER_3(vfp_touls, f32, f32, i32, env)
-DEF_HELPER_3(vfp_toshd, f64, f64, i32, env)
-DEF_HELPER_3(vfp_tosld, f64, f64, i32, env)
-DEF_HELPER_3(vfp_touhd, f64, f64, i32, env)
-DEF_HELPER_3(vfp_tould, f64, f64, i32, env)
-DEF_HELPER_3(vfp_shtos, f32, f32, i32, env)
-DEF_HELPER_3(vfp_sltos, f32, f32, i32, env)
-DEF_HELPER_3(vfp_uhtos, f32, f32, i32, env)
-DEF_HELPER_3(vfp_ultos, f32, f32, i32, env)
-DEF_HELPER_3(vfp_shtod, f64, f64, i32, env)
-DEF_HELPER_3(vfp_sltod, f64, f64, i32, env)
-DEF_HELPER_3(vfp_uhtod, f64, f64, i32, env)
-DEF_HELPER_3(vfp_ultod, f64, f64, i32, env)
-
-DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env)
-DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env)
-DEF_HELPER_2(neon_fcvt_f16_to_f32, f32, i32, env)
-DEF_HELPER_2(neon_fcvt_f32_to_f16, i32, f32, env)
-
-DEF_HELPER_3(recps_f32, f32, f32, f32, env)
-DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env)
-DEF_HELPER_2(recpe_f32, f32, f32, env)
-DEF_HELPER_2(rsqrte_f32, f32, f32, env)
-DEF_HELPER_2(recpe_u32, i32, i32, env)
-DEF_HELPER_2(rsqrte_u32, i32, i32, env)
-DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32)
-
-DEF_HELPER_2(add_cc, i32, i32, i32)
-DEF_HELPER_2(adc_cc, i32, i32, i32)
-DEF_HELPER_2(sub_cc, i32, i32, i32)
-DEF_HELPER_2(sbc_cc, i32, i32, i32)
-
-DEF_HELPER_2(shl, i32, i32, i32)
-DEF_HELPER_2(shr, i32, i32, i32)
-DEF_HELPER_2(sar, i32, i32, i32)
-DEF_HELPER_2(shl_cc, i32, i32, i32)
-DEF_HELPER_2(shr_cc, i32, i32, i32)
-DEF_HELPER_2(sar_cc, i32, i32, i32)
-DEF_HELPER_2(ror_cc, i32, i32, i32)
-
-/* neon_helper.c */
-DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32)
-DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32)
-DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qadd_u32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qadd_s32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32)
-DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32)
-DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qsub_u32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qsub_s32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qadd_u64, i64, env, i64, i64)
-DEF_HELPER_3(neon_qadd_s64, i64, env, i64, i64)
-DEF_HELPER_3(neon_qsub_u64, i64, env, i64, i64)
-DEF_HELPER_3(neon_qsub_s64, i64, env, i64, i64)
-
-DEF_HELPER_2(neon_hadd_s8, i32, i32, i32)
-DEF_HELPER_2(neon_hadd_u8, i32, i32, i32)
-DEF_HELPER_2(neon_hadd_s16, i32, i32, i32)
-DEF_HELPER_2(neon_hadd_u16, i32, i32, i32)
-DEF_HELPER_2(neon_hadd_s32, s32, s32, s32)
-DEF_HELPER_2(neon_hadd_u32, i32, i32, i32)
-DEF_HELPER_2(neon_rhadd_s8, i32, i32, i32)
-DEF_HELPER_2(neon_rhadd_u8, i32, i32, i32)
-DEF_HELPER_2(neon_rhadd_s16, i32, i32, i32)
-DEF_HELPER_2(neon_rhadd_u16, i32, i32, i32)
-DEF_HELPER_2(neon_rhadd_s32, s32, s32, s32)
-DEF_HELPER_2(neon_rhadd_u32, i32, i32, i32)
-DEF_HELPER_2(neon_hsub_s8, i32, i32, i32)
-DEF_HELPER_2(neon_hsub_u8, i32, i32, i32)
-DEF_HELPER_2(neon_hsub_s16, i32, i32, i32)
-DEF_HELPER_2(neon_hsub_u16, i32, i32, i32)
-DEF_HELPER_2(neon_hsub_s32, s32, s32, s32)
-DEF_HELPER_2(neon_hsub_u32, i32, i32, i32)
-
-DEF_HELPER_2(neon_cgt_u8, i32, i32, i32)
-DEF_HELPER_2(neon_cgt_s8, i32, i32, i32)
-DEF_HELPER_2(neon_cgt_u16, i32, i32, i32)
-DEF_HELPER_2(neon_cgt_s16, i32, i32, i32)
-DEF_HELPER_2(neon_cgt_u32, i32, i32, i32)
-DEF_HELPER_2(neon_cgt_s32, i32, i32, i32)
-DEF_HELPER_2(neon_cge_u8, i32, i32, i32)
-DEF_HELPER_2(neon_cge_s8, i32, i32, i32)
-DEF_HELPER_2(neon_cge_u16, i32, i32, i32)
-DEF_HELPER_2(neon_cge_s16, i32, i32, i32)
-DEF_HELPER_2(neon_cge_u32, i32, i32, i32)
-DEF_HELPER_2(neon_cge_s32, i32, i32, i32)
-
-DEF_HELPER_2(neon_min_u8, i32, i32, i32)
-DEF_HELPER_2(neon_min_s8, i32, i32, i32)
-DEF_HELPER_2(neon_min_u16, i32, i32, i32)
-DEF_HELPER_2(neon_min_s16, i32, i32, i32)
-DEF_HELPER_2(neon_min_u32, i32, i32, i32)
-DEF_HELPER_2(neon_min_s32, i32, i32, i32)
-DEF_HELPER_2(neon_max_u8, i32, i32, i32)
-DEF_HELPER_2(neon_max_s8, i32, i32, i32)
-DEF_HELPER_2(neon_max_u16, i32, i32, i32)
-DEF_HELPER_2(neon_max_s16, i32, i32, i32)
-DEF_HELPER_2(neon_max_u32, i32, i32, i32)
-DEF_HELPER_2(neon_max_s32, i32, i32, i32)
-DEF_HELPER_2(neon_pmin_u8, i32, i32, i32)
-DEF_HELPER_2(neon_pmin_s8, i32, i32, i32)
-DEF_HELPER_2(neon_pmin_u16, i32, i32, i32)
-DEF_HELPER_2(neon_pmin_s16, i32, i32, i32)
-DEF_HELPER_2(neon_pmax_u8, i32, i32, i32)
-DEF_HELPER_2(neon_pmax_s8, i32, i32, i32)
-DEF_HELPER_2(neon_pmax_u16, i32, i32, i32)
-DEF_HELPER_2(neon_pmax_s16, i32, i32, i32)
-
-DEF_HELPER_2(neon_abd_u8, i32, i32, i32)
-DEF_HELPER_2(neon_abd_s8, i32, i32, i32)
-DEF_HELPER_2(neon_abd_u16, i32, i32, i32)
-DEF_HELPER_2(neon_abd_s16, i32, i32, i32)
-DEF_HELPER_2(neon_abd_u32, i32, i32, i32)
-DEF_HELPER_2(neon_abd_s32, i32, i32, i32)
-
-DEF_HELPER_2(neon_shl_u8, i32, i32, i32)
-DEF_HELPER_2(neon_shl_s8, i32, i32, i32)
-DEF_HELPER_2(neon_shl_u16, i32, i32, i32)
-DEF_HELPER_2(neon_shl_s16, i32, i32, i32)
-DEF_HELPER_2(neon_shl_u32, i32, i32, i32)
-DEF_HELPER_2(neon_shl_s32, i32, i32, i32)
-DEF_HELPER_2(neon_shl_u64, i64, i64, i64)
-DEF_HELPER_2(neon_shl_s64, i64, i64, i64)
-DEF_HELPER_2(neon_rshl_u8, i32, i32, i32)
-DEF_HELPER_2(neon_rshl_s8, i32, i32, i32)
-DEF_HELPER_2(neon_rshl_u16, i32, i32, i32)
-DEF_HELPER_2(neon_rshl_s16, i32, i32, i32)
-DEF_HELPER_2(neon_rshl_u32, i32, i32, i32)
-DEF_HELPER_2(neon_rshl_s32, i32, i32, i32)
-DEF_HELPER_2(neon_rshl_u64, i64, i64, i64)
-DEF_HELPER_2(neon_rshl_s64, i64, i64, i64)
-DEF_HELPER_3(neon_qshl_u8, i32, env, i32, i32)
-DEF_HELPER_3(neon_qshl_s8, i32, env, i32, i32)
-DEF_HELPER_3(neon_qshl_u16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qshl_s16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64)
-DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64)
-DEF_HELPER_3(neon_qshlu_s8, i32, env, i32, i32);
-DEF_HELPER_3(neon_qshlu_s16, i32, env, i32, i32);
-DEF_HELPER_3(neon_qshlu_s32, i32, env, i32, i32);
-DEF_HELPER_3(neon_qshlu_s64, i64, env, i64, i64);
-DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32)
-DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32)
-DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qrshl_s16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qrshl_u32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qrshl_s32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qrshl_u64, i64, env, i64, i64)
-DEF_HELPER_3(neon_qrshl_s64, i64, env, i64, i64)
-
-DEF_HELPER_2(neon_add_u8, i32, i32, i32)
-DEF_HELPER_2(neon_add_u16, i32, i32, i32)
-DEF_HELPER_2(neon_padd_u8, i32, i32, i32)
-DEF_HELPER_2(neon_padd_u16, i32, i32, i32)
-DEF_HELPER_2(neon_sub_u8, i32, i32, i32)
-DEF_HELPER_2(neon_sub_u16, i32, i32, i32)
-DEF_HELPER_2(neon_mul_u8, i32, i32, i32)
-DEF_HELPER_2(neon_mul_u16, i32, i32, i32)
-DEF_HELPER_2(neon_mul_p8, i32, i32, i32)
-DEF_HELPER_2(neon_mull_p8, i64, i32, i32)
-
-DEF_HELPER_2(neon_tst_u8, i32, i32, i32)
-DEF_HELPER_2(neon_tst_u16, i32, i32, i32)
-DEF_HELPER_2(neon_tst_u32, i32, i32, i32)
-DEF_HELPER_2(neon_ceq_u8, i32, i32, i32)
-DEF_HELPER_2(neon_ceq_u16, i32, i32, i32)
-DEF_HELPER_2(neon_ceq_u32, i32, i32, i32)
-
-DEF_HELPER_1(neon_abs_s8, i32, i32)
-DEF_HELPER_1(neon_abs_s16, i32, i32)
-DEF_HELPER_1(neon_clz_u8, i32, i32)
-DEF_HELPER_1(neon_clz_u16, i32, i32)
-DEF_HELPER_1(neon_cls_s8, i32, i32)
-DEF_HELPER_1(neon_cls_s16, i32, i32)
-DEF_HELPER_1(neon_cls_s32, i32, i32)
-DEF_HELPER_1(neon_cnt_u8, i32, i32)
-
-DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32)
-DEF_HELPER_3(neon_qdmulh_s32, i32, env, i32, i32)
-DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32)
-
-DEF_HELPER_1(neon_narrow_u8, i32, i64)
-DEF_HELPER_1(neon_narrow_u16, i32, i64)
-DEF_HELPER_2(neon_unarrow_sat8, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64)
-DEF_HELPER_2(neon_unarrow_sat16, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64)
-DEF_HELPER_2(neon_unarrow_sat32, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64)
-DEF_HELPER_1(neon_narrow_high_u8, i32, i64)
-DEF_HELPER_1(neon_narrow_high_u16, i32, i64)
-DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64)
-DEF_HELPER_1(neon_narrow_round_high_u16, i32, i64)
-DEF_HELPER_1(neon_widen_u8, i64, i32)
-DEF_HELPER_1(neon_widen_s8, i64, i32)
-DEF_HELPER_1(neon_widen_u16, i64, i32)
-DEF_HELPER_1(neon_widen_s16, i64, i32)
-
-DEF_HELPER_2(neon_addl_u16, i64, i64, i64)
-DEF_HELPER_2(neon_addl_u32, i64, i64, i64)
-DEF_HELPER_2(neon_paddl_u16, i64, i64, i64)
-DEF_HELPER_2(neon_paddl_u32, i64, i64, i64)
-DEF_HELPER_2(neon_subl_u16, i64, i64, i64)
-DEF_HELPER_2(neon_subl_u32, i64, i64, i64)
-DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64)
-DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64)
-DEF_HELPER_2(neon_abdl_u16, i64, i32, i32)
-DEF_HELPER_2(neon_abdl_s16, i64, i32, i32)
-DEF_HELPER_2(neon_abdl_u32, i64, i32, i32)
-DEF_HELPER_2(neon_abdl_s32, i64, i32, i32)
-DEF_HELPER_2(neon_abdl_u64, i64, i32, i32)
-DEF_HELPER_2(neon_abdl_s64, i64, i32, i32)
-DEF_HELPER_2(neon_mull_u8, i64, i32, i32)
-DEF_HELPER_2(neon_mull_s8, i64, i32, i32)
-DEF_HELPER_2(neon_mull_u16, i64, i32, i32)
-DEF_HELPER_2(neon_mull_s16, i64, i32, i32)
-
-DEF_HELPER_1(neon_negl_u16, i64, i64)
-DEF_HELPER_1(neon_negl_u32, i64, i64)
-DEF_HELPER_1(neon_negl_u64, i64, i64)
-
-DEF_HELPER_2(neon_qabs_s8, i32, env, i32)
-DEF_HELPER_2(neon_qabs_s16, i32, env, i32)
-DEF_HELPER_2(neon_qabs_s32, i32, env, i32)
-DEF_HELPER_2(neon_qneg_s8, i32, env, i32)
-DEF_HELPER_2(neon_qneg_s16, i32, env, i32)
-DEF_HELPER_2(neon_qneg_s32, i32, env, i32)
-
-DEF_HELPER_2(neon_min_f32, i32, i32, i32)
-DEF_HELPER_2(neon_max_f32, i32, i32, i32)
-DEF_HELPER_2(neon_abd_f32, i32, i32, i32)
-DEF_HELPER_2(neon_add_f32, i32, i32, i32)
-DEF_HELPER_2(neon_sub_f32, i32, i32, i32)
-DEF_HELPER_2(neon_mul_f32, i32, i32, i32)
-DEF_HELPER_2(neon_ceq_f32, i32, i32, i32)
-DEF_HELPER_2(neon_cge_f32, i32, i32, i32)
-DEF_HELPER_2(neon_cgt_f32, i32, i32, i32)
-DEF_HELPER_2(neon_acge_f32, i32, i32, i32)
-DEF_HELPER_2(neon_acgt_f32, i32, i32, i32)
-
-/* iwmmxt_helper.c */
-DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64)
-DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64)
-DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64)
-
-#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \
-DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \
-DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \
-DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \
-
-DEF_IWMMXT_HELPER_SIZE_ENV(unpackl)
-DEF_IWMMXT_HELPER_SIZE_ENV(unpackh)
-
-DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64)
-DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64)
-
-DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq)
-DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu)
-DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts)
-
-DEF_IWMMXT_HELPER_SIZE_ENV(mins)
-DEF_IWMMXT_HELPER_SIZE_ENV(minu)
-DEF_IWMMXT_HELPER_SIZE_ENV(maxs)
-DEF_IWMMXT_HELPER_SIZE_ENV(maxu)
-
-DEF_IWMMXT_HELPER_SIZE_ENV(subn)
-DEF_IWMMXT_HELPER_SIZE_ENV(addn)
-DEF_IWMMXT_HELPER_SIZE_ENV(subu)
-DEF_IWMMXT_HELPER_SIZE_ENV(addu)
-DEF_IWMMXT_HELPER_SIZE_ENV(subs)
-DEF_IWMMXT_HELPER_SIZE_ENV(adds)
-
-DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64)
-DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64)
-DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64)
-DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64)
-
-DEF_HELPER_2(iwmmxt_msadb, i64, i64, i64)
-
-DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32)
-DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32)
-
-DEF_HELPER_1(iwmmxt_bcstb, i64, i32)
-DEF_HELPER_1(iwmmxt_bcstw, i64, i32)
-DEF_HELPER_1(iwmmxt_bcstl, i64, i32)
-
-DEF_HELPER_1(iwmmxt_addcb, i64, i64)
-DEF_HELPER_1(iwmmxt_addcw, i64, i64)
-DEF_HELPER_1(iwmmxt_addcl, i64, i64)
-
-DEF_HELPER_1(iwmmxt_msbb, i32, i64)
-DEF_HELPER_1(iwmmxt_msbw, i32, i64)
-DEF_HELPER_1(iwmmxt_msbl, i32, i64)
-
-DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32)
-DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32)
-
-DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64)
-DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64)
-DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64)
-DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64)
-DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64)
-DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64)
-
-DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32)
-DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32)
-DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32)
-
-DEF_HELPER_2(set_teecr, void, env, i32)
-
-DEF_HELPER_3(neon_unzip8, void, env, i32, i32)
-DEF_HELPER_3(neon_unzip16, void, env, i32, i32)
-DEF_HELPER_3(neon_qunzip8, void, env, i32, i32)
-DEF_HELPER_3(neon_qunzip16, void, env, i32, i32)
-DEF_HELPER_3(neon_qunzip32, void, env, i32, i32)
-DEF_HELPER_3(neon_zip8, void, env, i32, i32)
-DEF_HELPER_3(neon_zip16, void, env, i32, i32)
-DEF_HELPER_3(neon_qzip8, void, env, i32, i32)
-DEF_HELPER_3(neon_qzip16, void, env, i32, i32)
-DEF_HELPER_3(neon_qzip32, void, env, i32, i32)
-
-#include "def-helper.h"
index 3332f708c96a679f227cf2acf8debcc4e16879b1..ebe6eb9fae221f4a57ebe6c2c5e01fae3020952a 100644 (file)
@@ -23,8 +23,8 @@
 #include <stdio.h>
 
 #include "cpu.h"
-#include "exec-all.h"
-#include "helpers.h"
+#include "exec.h"
+#include "helper.h"
 
 /* iwMMXt macros extracted from GNU gdb.  */
 
@@ -162,8 +162,7 @@ uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b)
     SIMD64_SET(NBIT64(x), SIMD_NBIT) | \
     SIMD64_SET(ZBIT64(x), SIMD_ZBIT)
 #define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3)                        \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUState *env, \
-                                                 uint64_t a, uint64_t b) \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(uint64_t a, uint64_t b) \
 {                                                              \
     a =                                                                \
         (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) |      \
@@ -177,8 +176,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUState *env, \
         NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);               \
     return a;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUState *env, \
-                                        uint64_t a, uint64_t b) \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(uint64_t a, uint64_t b) \
 {                                                              \
     a =                                                                \
         (((a >> SH0) & 0xffff) << 0) |                         \
@@ -190,8 +188,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUState *env, \
         NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3);               \
     return a;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUState *env, \
-                                        uint64_t a, uint64_t b) \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(uint64_t a, uint64_t b) \
 {                                                              \
     a =                                                                \
         (((a >> SH0) & 0xffffffff) << 0) |                     \
@@ -200,8 +197,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUState *env, \
         NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);              \
     return a;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUState *env, \
-                                                  uint64_t x)   \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(uint64_t x)   \
 {                                                              \
     x =                                                                \
         (((x >> SH0) & 0xff) << 0) |                           \
@@ -213,8 +209,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUState *env, \
         NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);             \
     return x;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUState *env, \
-                                                  uint64_t x)   \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(uint64_t x)   \
 {                                                              \
     x =                                                                \
         (((x >> SH0) & 0xffff) << 0) |                         \
@@ -223,15 +218,13 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUState *env, \
         NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);              \
     return x;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUState *env, \
-                                                  uint64_t x)   \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(uint64_t x)   \
 {                                                              \
     x = (((x >> SH0) & 0xffffffff) << 0);                      \
     env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0);     \
     return x;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUState *env, \
-                                                  uint64_t x)   \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(uint64_t x)   \
 {                                                              \
     x =                                                                \
         ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) |                \
@@ -243,8 +236,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUState *env, \
         NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);             \
     return x;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUState *env, \
-                                                  uint64_t x)   \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(uint64_t x)   \
 {                                                              \
     x =                                                                \
         ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) |      \
@@ -253,8 +245,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUState *env, \
         NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);              \
     return x;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUState *env, \
-                                                  uint64_t x)   \
+uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(uint64_t x)   \
 {                                                              \
     x = EXTEND32((x >> SH0) & 0xffffffff);                     \
     env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0);     \
@@ -264,8 +255,7 @@ IWMMXT_OP_UNPACK(l, 0, 8, 16, 24)
 IWMMXT_OP_UNPACK(h, 32, 40, 48, 56)
 
 #define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O)                     \
-uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUState *env,    \
-                                        uint64_t a, uint64_t b) \
+uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(uint64_t a, uint64_t b) \
 {                                                              \
     a =                                                                \
         CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) |            \
@@ -279,8 +269,7 @@ uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUState *env,    \
         NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);               \
     return a;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUState *env,    \
-                                        uint64_t a, uint64_t b) \
+uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(uint64_t a, uint64_t b) \
 {                                                              \
     a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) |       \
         CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff);       \
@@ -289,8 +278,7 @@ uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUState *env,    \
         NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3);             \
     return a;                                                   \
 }                                                              \
-uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUState *env,    \
-                                        uint64_t a, uint64_t b) \
+uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(uint64_t a, uint64_t b) \
 {                                                              \
     a = CMP(0, Tl, O, 0xffffffff) |                            \
         CMP(32, Tl, O, 0xffffffff);                            \
@@ -329,7 +317,7 @@ IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +)
 #define AVGB(SHR) ((( \
         ((a >> SHR) & 0xff) + ((b >> SHR) & 0xff) + round) >> 1) << SHR)
 #define IWMMXT_OP_AVGB(r)                                                 \
-uint64_t HELPER(iwmmxt_avgb##r)(CPUState *env, uint64_t a, uint64_t b)    \
+uint64_t HELPER(iwmmxt_avgb##r)(uint64_t a, uint64_t b)                   \
 {                                                                         \
     const int round = r;                                                  \
     a = AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) |                         \
@@ -353,7 +341,7 @@ IWMMXT_OP_AVGB(1)
 #define AVGW(SHR) ((( \
         ((a >> SHR) & 0xffff) + ((b >> SHR) & 0xffff) + round) >> 1) << SHR)
 #define IWMMXT_OP_AVGW(r)                                               \
-uint64_t HELPER(iwmmxt_avgw##r)(CPUState *env, uint64_t a, uint64_t b)  \
+uint64_t HELPER(iwmmxt_avgw##r)(uint64_t a, uint64_t b)                 \
 {                                                                       \
     const int round = r;                                                \
     a = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48);                       \
@@ -464,7 +452,7 @@ uint32_t HELPER(iwmmxt_msbl)(uint64_t x)
 }
 
 /* FIXME: Split wCASF setting into a separate op to avoid env use.  */
-uint64_t HELPER(iwmmxt_srlw)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_srlw)(uint64_t x, uint32_t n)
 {
     x = (((x & (0xffffll << 0)) >> n) & (0xffffll << 0)) |
         (((x & (0xffffll << 16)) >> n) & (0xffffll << 16)) |
@@ -476,7 +464,7 @@ uint64_t HELPER(iwmmxt_srlw)(CPUState *env, uint64_t x, uint32_t n)
     return x;
 }
 
-uint64_t HELPER(iwmmxt_srll)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_srll)(uint64_t x, uint32_t n)
 {
     x = ((x & (0xffffffffll << 0)) >> n) |
         ((x >> n) & (0xffffffffll << 32));
@@ -485,14 +473,14 @@ uint64_t HELPER(iwmmxt_srll)(CPUState *env, uint64_t x, uint32_t n)
     return x;
 }
 
-uint64_t HELPER(iwmmxt_srlq)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_srlq)(uint64_t x, uint32_t n)
 {
     x >>= n;
     env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
     return x;
 }
 
-uint64_t HELPER(iwmmxt_sllw)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_sllw)(uint64_t x, uint32_t n)
 {
     x = (((x & (0xffffll << 0)) << n) & (0xffffll << 0)) |
         (((x & (0xffffll << 16)) << n) & (0xffffll << 16)) |
@@ -504,7 +492,7 @@ uint64_t HELPER(iwmmxt_sllw)(CPUState *env, uint64_t x, uint32_t n)
     return x;
 }
 
-uint64_t HELPER(iwmmxt_slll)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_slll)(uint64_t x, uint32_t n)
 {
     x = ((x << n) & (0xffffffffll << 0)) |
         ((x & (0xffffffffll << 32)) << n);
@@ -513,14 +501,14 @@ uint64_t HELPER(iwmmxt_slll)(CPUState *env, uint64_t x, uint32_t n)
     return x;
 }
 
-uint64_t HELPER(iwmmxt_sllq)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_sllq)(uint64_t x, uint32_t n)
 {
     x <<= n;
     env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
     return x;
 }
 
-uint64_t HELPER(iwmmxt_sraw)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_sraw)(uint64_t x, uint32_t n)
 {
     x = ((uint64_t) ((EXTEND16(x >> 0) >> n) & 0xffff) << 0) |
         ((uint64_t) ((EXTEND16(x >> 16) >> n) & 0xffff) << 16) |
@@ -532,7 +520,7 @@ uint64_t HELPER(iwmmxt_sraw)(CPUState *env, uint64_t x, uint32_t n)
     return x;
 }
 
-uint64_t HELPER(iwmmxt_sral)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_sral)(uint64_t x, uint32_t n)
 {
     x = (((EXTEND32(x >> 0) >> n) & 0xffffffff) << 0) |
         (((EXTEND32(x >> 32) >> n) & 0xffffffff) << 32);
@@ -541,14 +529,14 @@ uint64_t HELPER(iwmmxt_sral)(CPUState *env, uint64_t x, uint32_t n)
     return x;
 }
 
-uint64_t HELPER(iwmmxt_sraq)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_sraq)(uint64_t x, uint32_t n)
 {
     x = (int64_t) x >> n;
     env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
     return x;
 }
 
-uint64_t HELPER(iwmmxt_rorw)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_rorw)(uint64_t x, uint32_t n)
 {
     x = ((((x & (0xffffll << 0)) >> n) |
           ((x & (0xffffll << 0)) << (16 - n))) & (0xffffll << 0)) |
@@ -564,7 +552,7 @@ uint64_t HELPER(iwmmxt_rorw)(CPUState *env, uint64_t x, uint32_t n)
     return x;
 }
 
-uint64_t HELPER(iwmmxt_rorl)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_rorl)(uint64_t x, uint32_t n)
 {
     x = ((x & (0xffffffffll << 0)) >> n) |
         ((x >> n) & (0xffffffffll << 32)) |
@@ -575,14 +563,14 @@ uint64_t HELPER(iwmmxt_rorl)(CPUState *env, uint64_t x, uint32_t n)
     return x;
 }
 
-uint64_t HELPER(iwmmxt_rorq)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_rorq)(uint64_t x, uint32_t n)
 {
     x = (x >> n) | (x << (64 - n));
     env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x);
     return x;
 }
 
-uint64_t HELPER(iwmmxt_shufh)(CPUState *env, uint64_t x, uint32_t n)
+uint64_t HELPER(iwmmxt_shufh)(uint64_t x, uint32_t n)
 {
     x = (((x >> ((n << 4) & 0x30)) & 0xffff) << 0) |
         (((x >> ((n << 2) & 0x30)) & 0xffff) << 16) |
@@ -595,7 +583,7 @@ uint64_t HELPER(iwmmxt_shufh)(CPUState *env, uint64_t x, uint32_t n)
 }
 
 /* TODO: Unsigned-Saturation */
-uint64_t HELPER(iwmmxt_packuw)(CPUState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(iwmmxt_packuw)(uint64_t a, uint64_t b)
 {
     a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) |
         (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) |
@@ -609,7 +597,7 @@ uint64_t HELPER(iwmmxt_packuw)(CPUState *env, uint64_t a, uint64_t b)
     return a;
 }
 
-uint64_t HELPER(iwmmxt_packul)(CPUState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(iwmmxt_packul)(uint64_t a, uint64_t b)
 {
     a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) |
         (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48);
@@ -619,7 +607,7 @@ uint64_t HELPER(iwmmxt_packul)(CPUState *env, uint64_t a, uint64_t b)
     return a;
 }
 
-uint64_t HELPER(iwmmxt_packuq)(CPUState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(iwmmxt_packuq)(uint64_t a, uint64_t b)
 {
     a = (a & 0xffffffff) | ((b & 0xffffffff) << 32);
     env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
@@ -628,7 +616,7 @@ uint64_t HELPER(iwmmxt_packuq)(CPUState *env, uint64_t a, uint64_t b)
 }
 
 /* TODO: Signed-Saturation */
-uint64_t HELPER(iwmmxt_packsw)(CPUState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(iwmmxt_packsw)(uint64_t a, uint64_t b)
 {
     a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) |
         (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) |
@@ -642,7 +630,7 @@ uint64_t HELPER(iwmmxt_packsw)(CPUState *env, uint64_t a, uint64_t b)
     return a;
 }
 
-uint64_t HELPER(iwmmxt_packsl)(CPUState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(iwmmxt_packsl)(uint64_t a, uint64_t b)
 {
     a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) |
         (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48);
@@ -652,7 +640,7 @@ uint64_t HELPER(iwmmxt_packsl)(CPUState *env, uint64_t a, uint64_t b)
     return a;
 }
 
-uint64_t HELPER(iwmmxt_packsq)(CPUState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(iwmmxt_packsq)(uint64_t a, uint64_t b)
 {
     a = (a & 0xffffffff) | ((b & 0xffffffff) << 32);
     env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
index 002a9c11a63f2581bcd9000cf1bfda29bf96ccca..f5b173aa71d6ec2b19e70570c6527caa71c3c847 100644 (file)
 #include <stdio.h>
 
 #include "cpu.h"
-#include "exec-all.h"
-#include "helpers.h"
+#include "exec.h"
+#include "helper.h"
 
 #define SIGNBIT (uint32_t)0x80000000
 #define SIGNBIT64 ((uint64_t)1 << 63)
 
 #define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] = CPSR_Q
 
-static float_status neon_float_status;
-#define NFS &neon_float_status
-
-/* Helper routines to perform bitwise copies between float and int.  */
-static inline float32 vfp_itos(uint32_t i)
-{
-    union {
-        uint32_t i;
-        float32 s;
-    } v;
-
-    v.i = i;
-    return v.s;
-}
-
-static inline uint32_t vfp_stoi(float32 s)
-{
-    union {
-        uint32_t i;
-        float32 s;
-    } v;
-
-    v.s = s;
-    return v.i;
-}
+#define NFS (&env->vfp.standard_fp_status)
 
 #define NEON_TYPE1(name, type) \
 typedef struct \
@@ -139,10 +115,6 @@ NEON_TYPE1(u32, uint32_t)
 uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \
 NEON_VOP_BODY(vtype, n)
 
-#define NEON_VOP_ENV(name, vtype, n) \
-uint32_t HELPER(glue(neon_,name))(CPUState *env, uint32_t arg1, uint32_t arg2) \
-NEON_VOP_BODY(vtype, n)
-
 /* Pairwise operations.  */
 /* For 32-bit elements each segment only contains a single element, so
    the elementwise and pairwise operations are the same.  */
@@ -191,14 +163,14 @@ uint32_t HELPER(glue(neon_,name))(uint32_t arg) \
         dest = tmp; \
     }} while(0)
 #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t)
-NEON_VOP_ENV(qadd_u8, neon_u8, 4)
+NEON_VOP(qadd_u8, neon_u8, 4)
 #undef NEON_FN
 #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t)
-NEON_VOP_ENV(qadd_u16, neon_u16, 2)
+NEON_VOP(qadd_u16, neon_u16, 2)
 #undef NEON_FN
 #undef NEON_USAT
 
-uint32_t HELPER(neon_qadd_u32)(CPUState *env, uint32_t a, uint32_t b)
+uint32_t HELPER(neon_qadd_u32)(uint32_t a, uint32_t b)
 {
     uint32_t res = a + b;
     if (res < a) {
@@ -208,7 +180,7 @@ uint32_t HELPER(neon_qadd_u32)(CPUState *env, uint32_t a, uint32_t b)
     return res;
 }
 
-uint64_t HELPER(neon_qadd_u64)(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t HELPER(neon_qadd_u64)(uint64_t src1, uint64_t src2)
 {
     uint64_t res;
 
@@ -233,14 +205,14 @@ uint64_t HELPER(neon_qadd_u64)(CPUState *env, uint64_t src1, uint64_t src2)
     dest = tmp; \
     } while(0)
 #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t)
-NEON_VOP_ENV(qadd_s8, neon_s8, 4)
+NEON_VOP(qadd_s8, neon_s8, 4)
 #undef NEON_FN
 #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t)
-NEON_VOP_ENV(qadd_s16, neon_s16, 2)
+NEON_VOP(qadd_s16, neon_s16, 2)
 #undef NEON_FN
 #undef NEON_SSAT
 
-uint32_t HELPER(neon_qadd_s32)(CPUState *env, uint32_t a, uint32_t b)
+uint32_t HELPER(neon_qadd_s32)(uint32_t a, uint32_t b)
 {
     uint32_t res = a + b;
     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
@@ -250,7 +222,7 @@ uint32_t HELPER(neon_qadd_s32)(CPUState *env, uint32_t a, uint32_t b)
     return res;
 }
 
-uint64_t HELPER(neon_qadd_s64)(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t HELPER(neon_qadd_s64)(uint64_t src1, uint64_t src2)
 {
     uint64_t res;
 
@@ -271,14 +243,14 @@ uint64_t HELPER(neon_qadd_s64)(CPUState *env, uint64_t src1, uint64_t src2)
         dest = tmp; \
     }} while(0)
 #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t)
-NEON_VOP_ENV(qsub_u8, neon_u8, 4)
+NEON_VOP(qsub_u8, neon_u8, 4)
 #undef NEON_FN
 #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t)
-NEON_VOP_ENV(qsub_u16, neon_u16, 2)
+NEON_VOP(qsub_u16, neon_u16, 2)
 #undef NEON_FN
 #undef NEON_USAT
 
-uint32_t HELPER(neon_qsub_u32)(CPUState *env, uint32_t a, uint32_t b)
+uint32_t HELPER(neon_qsub_u32)(uint32_t a, uint32_t b)
 {
     uint32_t res = a - b;
     if (res > a) {
@@ -288,7 +260,7 @@ uint32_t HELPER(neon_qsub_u32)(CPUState *env, uint32_t a, uint32_t b)
     return res;
 }
 
-uint64_t HELPER(neon_qsub_u64)(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t HELPER(neon_qsub_u64)(uint64_t src1, uint64_t src2)
 {
     uint64_t res;
 
@@ -314,14 +286,14 @@ uint64_t HELPER(neon_qsub_u64)(CPUState *env, uint64_t src1, uint64_t src2)
     dest = tmp; \
     } while(0)
 #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t)
-NEON_VOP_ENV(qsub_s8, neon_s8, 4)
+NEON_VOP(qsub_s8, neon_s8, 4)
 #undef NEON_FN
 #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t)
-NEON_VOP_ENV(qsub_s16, neon_s16, 2)
+NEON_VOP(qsub_s16, neon_s16, 2)
 #undef NEON_FN
 #undef NEON_SSAT
 
-uint32_t HELPER(neon_qsub_s32)(CPUState *env, uint32_t a, uint32_t b)
+uint32_t HELPER(neon_qsub_s32)(uint32_t a, uint32_t b)
 {
     uint32_t res = a - b;
     if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
@@ -331,7 +303,7 @@ uint32_t HELPER(neon_qsub_s32)(CPUState *env, uint32_t a, uint32_t b)
     return res;
 }
 
-uint64_t HELPER(neon_qsub_s64)(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t HELPER(neon_qsub_s64)(uint64_t src1, uint64_t src2)
 {
     uint64_t res;
 
@@ -682,12 +654,12 @@ uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
             dest = ~0; \
         } \
     }} while (0)
-NEON_VOP_ENV(qshl_u8, neon_u8, 4)
-NEON_VOP_ENV(qshl_u16, neon_u16, 2)
-NEON_VOP_ENV(qshl_u32, neon_u32, 1)
+NEON_VOP(qshl_u8, neon_u8, 4)
+NEON_VOP(qshl_u16, neon_u16, 2)
+NEON_VOP(qshl_u32, neon_u32, 1)
 #undef NEON_FN
 
-uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
+uint64_t HELPER(neon_qshl_u64)(uint64_t val, uint64_t shiftop)
 {
     int8_t shift = (int8_t)shiftop;
     if (shift >= 64) {
@@ -737,12 +709,12 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
             } \
         } \
     }} while (0)
-NEON_VOP_ENV(qshl_s8, neon_s8, 4)
-NEON_VOP_ENV(qshl_s16, neon_s16, 2)
-NEON_VOP_ENV(qshl_s32, neon_s32, 1)
+NEON_VOP(qshl_s8, neon_s8, 4)
+NEON_VOP(qshl_s16, neon_s16, 2)
+NEON_VOP(qshl_s32, neon_s32, 1)
 #undef NEON_FN
 
-uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+uint64_t HELPER(neon_qshl_s64)(uint64_t valop, uint64_t shiftop)
 {
     int8_t shift = (uint8_t)shiftop;
     int64_t val = valop;
@@ -792,26 +764,26 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
             } \
         } \
     }} while (0)
-NEON_VOP_ENV(qshlu_s8, neon_u8, 4)
-NEON_VOP_ENV(qshlu_s16, neon_u16, 2)
+NEON_VOP(qshlu_s8, neon_u8, 4)
+NEON_VOP(qshlu_s16, neon_u16, 2)
 #undef NEON_FN
 
-uint32_t HELPER(neon_qshlu_s32)(CPUState *env, uint32_t valop, uint32_t shiftop)
+uint32_t HELPER(neon_qshlu_s32)(uint32_t valop, uint32_t shiftop)
 {
     if ((int32_t)valop < 0) {
         SET_QC();
         return 0;
     }
-    return helper_neon_qshl_u32(env, valop, shiftop);
+    return helper_neon_qshl_u32(valop, shiftop);
 }
 
-uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+uint64_t HELPER(neon_qshlu_s64)(uint64_t valop, uint64_t shiftop)
 {
     if ((int64_t)valop < 0) {
         SET_QC();
         return 0;
     }
-    return helper_neon_qshl_u64(env, valop, shiftop);
+    return helper_neon_qshl_u64(valop, shiftop);
 }
 
 /* FIXME: This is wrong.  */
@@ -838,13 +810,13 @@ uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
             dest = ~0; \
         } \
     }} while (0)
-NEON_VOP_ENV(qrshl_u8, neon_u8, 4)
-NEON_VOP_ENV(qrshl_u16, neon_u16, 2)
+NEON_VOP(qrshl_u8, neon_u8, 4)
+NEON_VOP(qrshl_u16, neon_u16, 2)
 #undef NEON_FN
 
 /* The addition of the rounding constant may overflow, so we use an
  * intermediate 64 bits accumulator.  */
-uint32_t HELPER(neon_qrshl_u32)(CPUState *env, uint32_t val, uint32_t shiftop)
+uint32_t HELPER(neon_qrshl_u32)(uint32_t val, uint32_t shiftop)
 {
     uint32_t dest;
     int8_t shift = (int8_t)shiftop;
@@ -874,7 +846,7 @@ uint32_t HELPER(neon_qrshl_u32)(CPUState *env, uint32_t val, uint32_t shiftop)
 
 /* Handling addition overflow with 64 bits inputs values is more
  * tricky than with 32 bits values.  */
-uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
+uint64_t HELPER(neon_qrshl_u64)(uint64_t val, uint64_t shiftop)
 {
     int8_t shift = (int8_t)shiftop;
     if (shift >= 64) {
@@ -935,13 +907,13 @@ uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
             } \
         } \
     }} while (0)
-NEON_VOP_ENV(qrshl_s8, neon_s8, 4)
-NEON_VOP_ENV(qrshl_s16, neon_s16, 2)
+NEON_VOP(qrshl_s8, neon_s8, 4)
+NEON_VOP(qrshl_s16, neon_s16, 2)
 #undef NEON_FN
 
 /* The addition of the rounding constant may overflow, so we use an
  * intermediate 64 bits accumulator.  */
-uint32_t HELPER(neon_qrshl_s32)(CPUState *env, uint32_t valop, uint32_t shiftop)
+uint32_t HELPER(neon_qrshl_s32)(uint32_t valop, uint32_t shiftop)
 {
     int32_t dest;
     int32_t val = (int32_t)valop;
@@ -970,7 +942,7 @@ uint32_t HELPER(neon_qrshl_s32)(CPUState *env, uint32_t valop, uint32_t shiftop)
 
 /* Handling addition overflow with 64 bits inputs values is more
  * tricky than with 32 bits values.  */
-uint64_t HELPER(neon_qrshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+uint64_t HELPER(neon_qrshl_s64)(uint64_t valop, uint64_t shiftop)
 {
     int8_t shift = (uint8_t)shiftop;
     int64_t val = valop;
@@ -1179,10 +1151,10 @@ uint32_t HELPER(neon_cnt_u8)(uint32_t x)
     dest = tmp >> 16; \
     } while(0)
 #define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0)
-NEON_VOP_ENV(qdmulh_s16, neon_s16, 2)
+NEON_VOP(qdmulh_s16, neon_s16, 2)
 #undef NEON_FN
 #define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1)
-NEON_VOP_ENV(qrdmulh_s16, neon_s16, 2)
+NEON_VOP(qrdmulh_s16, neon_s16, 2)
 #undef NEON_FN
 #undef NEON_QDMULH16
 
@@ -1205,10 +1177,10 @@ NEON_VOP_ENV(qrdmulh_s16, neon_s16, 2)
     dest = tmp >> 32; \
     } while(0)
 #define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0)
-NEON_VOP_ENV(qdmulh_s32, neon_s32, 1)
+NEON_VOP(qdmulh_s32, neon_s32, 1)
 #undef NEON_FN
 #define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1)
-NEON_VOP_ENV(qrdmulh_s32, neon_s32, 1)
+NEON_VOP(qrdmulh_s32, neon_s32, 1)
 #undef NEON_FN
 #undef NEON_QDMULH32
 
@@ -1249,7 +1221,7 @@ uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x)
     return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000);
 }
 
-uint32_t HELPER(neon_unarrow_sat8)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_unarrow_sat8)(uint64_t x)
 {
     uint16_t s;
     uint8_t d;
@@ -1276,7 +1248,7 @@ uint32_t HELPER(neon_unarrow_sat8)(CPUState *env, uint64_t x)
     return res;
 }
 
-uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_narrow_sat_u8)(uint64_t x)
 {
     uint16_t s;
     uint8_t d;
@@ -1299,7 +1271,7 @@ uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x)
     return res;
 }
 
-uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_narrow_sat_s8)(uint64_t x)
 {
     int16_t s;
     uint8_t d;
@@ -1322,7 +1294,7 @@ uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x)
     return res;
 }
 
-uint32_t HELPER(neon_unarrow_sat16)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_unarrow_sat16)(uint64_t x)
 {
     uint32_t high;
     uint32_t low;
@@ -1345,7 +1317,7 @@ uint32_t HELPER(neon_unarrow_sat16)(CPUState *env, uint64_t x)
     return low | (high << 16);
 }
 
-uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_narrow_sat_u16)(uint64_t x)
 {
     uint32_t high;
     uint32_t low;
@@ -1362,7 +1334,7 @@ uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x)
     return low | (high << 16);
 }
 
-uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_narrow_sat_s16)(uint64_t x)
 {
     int32_t low;
     int32_t high;
@@ -1379,7 +1351,7 @@ uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x)
     return (uint16_t)low | (high << 16);
 }
 
-uint32_t HELPER(neon_unarrow_sat32)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_unarrow_sat32)(uint64_t x)
 {
     if (x & 0x8000000000000000ull) {
         SET_QC();
@@ -1392,7 +1364,7 @@ uint32_t HELPER(neon_unarrow_sat32)(CPUState *env, uint64_t x)
     return x;
 }
 
-uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_narrow_sat_u32)(uint64_t x)
 {
     if (x > 0xffffffffu) {
         SET_QC();
@@ -1401,7 +1373,7 @@ uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x)
     return x;
 }
 
-uint32_t HELPER(neon_narrow_sat_s32)(CPUState *env, uint64_t x)
+uint32_t HELPER(neon_narrow_sat_s32)(uint64_t x)
 {
     if ((int64_t)x != (int32_t)x) {
         SET_QC();
@@ -1508,7 +1480,7 @@ uint64_t HELPER(neon_subl_u32)(uint64_t a, uint64_t b)
     return (a - b) ^ mask;
 }
 
-uint64_t HELPER(neon_addl_saturate_s32)(CPUState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(neon_addl_saturate_s32)(uint64_t a, uint64_t b)
 {
     uint32_t x, y;
     uint32_t low, high;
@@ -1530,7 +1502,7 @@ uint64_t HELPER(neon_addl_saturate_s32)(CPUState *env, uint64_t a, uint64_t b)
     return low | ((uint64_t)high << 32);
 }
 
-uint64_t HELPER(neon_addl_saturate_s64)(CPUState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(neon_addl_saturate_s64)(uint64_t a, uint64_t b)
 {
     uint64_t result;
 
@@ -1542,9 +1514,13 @@ uint64_t HELPER(neon_addl_saturate_s64)(CPUState *env, uint64_t a, uint64_t b)
     return result;
 }
 
-#define DO_ABD(dest, x, y, type) do { \
-    type tmp_x = x; \
-    type tmp_y = y; \
+/* We have to do the arithmetic in a larger type than
+ * the input type, because for example with a signed 32 bit
+ * op the absolute difference can overflow a signed 32 bit value.
+ */
+#define DO_ABD(dest, x, y, intype, arithtype) do {            \
+    arithtype tmp_x = (intype)(x);                            \
+    arithtype tmp_y = (intype)(y);                            \
     dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \
     } while(0)
 
@@ -1552,12 +1528,12 @@ uint64_t HELPER(neon_abdl_u16)(uint32_t a, uint32_t b)
 {
     uint64_t tmp;
     uint64_t result;
-    DO_ABD(result, a, b, uint8_t);
-    DO_ABD(tmp, a >> 8, b >> 8, uint8_t);
+    DO_ABD(result, a, b, uint8_t, uint32_t);
+    DO_ABD(tmp, a >> 8, b >> 8, uint8_t, uint32_t);
     result |= tmp << 16;
-    DO_ABD(tmp, a >> 16, b >> 16, uint8_t);
+    DO_ABD(tmp, a >> 16, b >> 16, uint8_t, uint32_t);
     result |= tmp << 32;
-    DO_ABD(tmp, a >> 24, b >> 24, uint8_t);
+    DO_ABD(tmp, a >> 24, b >> 24, uint8_t, uint32_t);
     result |= tmp << 48;
     return result;
 }
@@ -1566,12 +1542,12 @@ uint64_t HELPER(neon_abdl_s16)(uint32_t a, uint32_t b)
 {
     uint64_t tmp;
     uint64_t result;
-    DO_ABD(result, a, b, int8_t);
-    DO_ABD(tmp, a >> 8, b >> 8, int8_t);
+    DO_ABD(result, a, b, int8_t, int32_t);
+    DO_ABD(tmp, a >> 8, b >> 8, int8_t, int32_t);
     result |= tmp << 16;
-    DO_ABD(tmp, a >> 16, b >> 16, int8_t);
+    DO_ABD(tmp, a >> 16, b >> 16, int8_t, int32_t);
     result |= tmp << 32;
-    DO_ABD(tmp, a >> 24, b >> 24, int8_t);
+    DO_ABD(tmp, a >> 24, b >> 24, int8_t, int32_t);
     result |= tmp << 48;
     return result;
 }
@@ -1580,8 +1556,8 @@ uint64_t HELPER(neon_abdl_u32)(uint32_t a, uint32_t b)
 {
     uint64_t tmp;
     uint64_t result;
-    DO_ABD(result, a, b, uint16_t);
-    DO_ABD(tmp, a >> 16, b >> 16, uint16_t);
+    DO_ABD(result, a, b, uint16_t, uint32_t);
+    DO_ABD(tmp, a >> 16, b >> 16, uint16_t, uint32_t);
     return result | (tmp << 32);
 }
 
@@ -1589,22 +1565,22 @@ uint64_t HELPER(neon_abdl_s32)(uint32_t a, uint32_t b)
 {
     uint64_t tmp;
     uint64_t result;
-    DO_ABD(result, a, b, int16_t);
-    DO_ABD(tmp, a >> 16, b >> 16, int16_t);
+    DO_ABD(result, a, b, int16_t, int32_t);
+    DO_ABD(tmp, a >> 16, b >> 16, int16_t, int32_t);
     return result | (tmp << 32);
 }
 
 uint64_t HELPER(neon_abdl_u64)(uint32_t a, uint32_t b)
 {
     uint64_t result;
-    DO_ABD(result, a, b, uint32_t);
+    DO_ABD(result, a, b, uint32_t, uint64_t);
     return result;
 }
 
 uint64_t HELPER(neon_abdl_s64)(uint32_t a, uint32_t b)
 {
     uint64_t result;
-    DO_ABD(result, a, b, int32_t);
+    DO_ABD(result, a, b, int32_t, int64_t);
     return result;
 }
 #undef DO_ABD
@@ -1702,7 +1678,7 @@ uint64_t HELPER(neon_negl_u64)(uint64_t x)
     } else if (x < 0) { \
         x = -x; \
     }} while (0)
-uint32_t HELPER(neon_qabs_s8)(CPUState *env, uint32_t x)
+uint32_t HELPER(neon_qabs_s8)(uint32_t x)
 {
     neon_s8 vec;
     NEON_UNPACK(neon_s8, vec, x);
@@ -1722,7 +1698,7 @@ uint32_t HELPER(neon_qabs_s8)(CPUState *env, uint32_t x)
     } else { \
         x = -x; \
     }} while (0)
-uint32_t HELPER(neon_qneg_s8)(CPUState *env, uint32_t x)
+uint32_t HELPER(neon_qneg_s8)(uint32_t x)
 {
     neon_s8 vec;
     NEON_UNPACK(neon_s8, vec, x);
@@ -1742,7 +1718,7 @@ uint32_t HELPER(neon_qneg_s8)(CPUState *env, uint32_t x)
     } else if (x < 0) { \
         x = -x; \
     }} while (0)
-uint32_t HELPER(neon_qabs_s16)(CPUState *env, uint32_t x)
+uint32_t HELPER(neon_qabs_s16)(uint32_t x)
 {
     neon_s16 vec;
     NEON_UNPACK(neon_s16, vec, x);
@@ -1760,7 +1736,7 @@ uint32_t HELPER(neon_qabs_s16)(CPUState *env, uint32_t x)
     } else { \
         x = -x; \
     }} while (0)
-uint32_t HELPER(neon_qneg_s16)(CPUState *env, uint32_t x)
+uint32_t HELPER(neon_qneg_s16)(uint32_t x)
 {
     neon_s16 vec;
     NEON_UNPACK(neon_s16, vec, x);
@@ -1771,7 +1747,7 @@ uint32_t HELPER(neon_qneg_s16)(CPUState *env, uint32_t x)
 }
 #undef DO_QNEG16
 
-uint32_t HELPER(neon_qabs_s32)(CPUState *env, uint32_t x)
+uint32_t HELPER(neon_qabs_s32)(uint32_t x)
 {
     if (x == SIGNBIT) {
         SET_QC();
@@ -1782,7 +1758,7 @@ uint32_t HELPER(neon_qabs_s32)(CPUState *env, uint32_t x)
     return x;
 }
 
-uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x)
+uint32_t HELPER(neon_qneg_s32)(uint32_t x)
 {
     if (x == SIGNBIT) {
         SET_QC();
@@ -1796,73 +1772,76 @@ uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x)
 /* NEON Float helpers.  */
 uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b)
 {
-    float32 f0 = vfp_itos(a);
-    float32 f1 = vfp_itos(b);
-    return (float32_compare_quiet(f0, f1, NFS) == -1) ? a : b;
+    return float32_val(float32_min(make_float32(a), make_float32(b), NFS));
 }
 
 uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b)
 {
-    float32 f0 = vfp_itos(a);
-    float32 f1 = vfp_itos(b);
-    return (float32_compare_quiet(f0, f1, NFS) == 1) ? a : b;
+    return float32_val(float32_max(make_float32(a), make_float32(b), NFS));
 }
 
 uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b)
 {
-    float32 f0 = vfp_itos(a);
-    float32 f1 = vfp_itos(b);
-    return vfp_stoi((float32_compare_quiet(f0, f1, NFS) == 1)
-                    ? float32_sub(f0, f1, NFS)
-                    : float32_sub(f1, f0, NFS));
+    float32 f0 = make_float32(a);
+    float32 f1 = make_float32(b);
+    return float32_val(float32_abs(float32_sub(f0, f1, NFS)));
 }
 
 uint32_t HELPER(neon_add_f32)(uint32_t a, uint32_t b)
 {
-    return vfp_stoi(float32_add(vfp_itos(a), vfp_itos(b), NFS));
+    return float32_val(float32_add(make_float32(a), make_float32(b), NFS));
 }
 
 uint32_t HELPER(neon_sub_f32)(uint32_t a, uint32_t b)
 {
-    return vfp_stoi(float32_sub(vfp_itos(a), vfp_itos(b), NFS));
+    return float32_val(float32_sub(make_float32(a), make_float32(b), NFS));
 }
 
 uint32_t HELPER(neon_mul_f32)(uint32_t a, uint32_t b)
 {
-    return vfp_stoi(float32_mul(vfp_itos(a), vfp_itos(b), NFS));
+    return float32_val(float32_mul(make_float32(a), make_float32(b), NFS));
 }
 
 /* Floating point comparisons produce an integer result.  */
-#define NEON_VOP_FCMP(name, cmp) \
+#define NEON_VOP_FCMP(name, ok) \
 uint32_t HELPER(neon_##name)(uint32_t a, uint32_t b) \
 { \
-    if (float32_compare_quiet(vfp_itos(a), vfp_itos(b), NFS) cmp 0) \
-        return ~0; \
-    else \
-        return 0; \
+    switch (float32_compare_quiet(make_float32(a), make_float32(b), NFS)) { \
+    ok return ~0; \
+    default: return 0; \
+    } \
 }
 
-NEON_VOP_FCMP(ceq_f32, ==)
-NEON_VOP_FCMP(cge_f32, >=)
-NEON_VOP_FCMP(cgt_f32, >)
+NEON_VOP_FCMP(ceq_f32, case float_relation_equal:)
+NEON_VOP_FCMP(cge_f32, case float_relation_equal: case float_relation_greater:)
+NEON_VOP_FCMP(cgt_f32, case float_relation_greater:)
 
 uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b)
 {
-    float32 f0 = float32_abs(vfp_itos(a));
-    float32 f1 = float32_abs(vfp_itos(b));
-    return (float32_compare_quiet(f0, f1,NFS) >= 0) ? ~0 : 0;
+    float32 f0 = float32_abs(make_float32(a));
+    float32 f1 = float32_abs(make_float32(b));
+    switch (float32_compare_quiet(f0, f1, NFS)) {
+    case float_relation_equal:
+    case float_relation_greater:
+        return ~0;
+    default:
+        return 0;
+    }
 }
 
 uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b)
 {
-    float32 f0 = float32_abs(vfp_itos(a));
-    float32 f1 = float32_abs(vfp_itos(b));
-    return (float32_compare_quiet(f0, f1, NFS) > 0) ? ~0 : 0;
+    float32 f0 = float32_abs(make_float32(a));
+    float32 f1 = float32_abs(make_float32(b));
+    if (float32_compare_quiet(f0, f1, NFS) == float_relation_greater) {
+        return ~0;
+    }
+    return 0;
 }
 
 #define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
 
-void HELPER(neon_qunzip8)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qunzip8)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm0 = float64_val(env->vfp.regs[rm]);
     uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
@@ -1890,7 +1869,7 @@ void HELPER(neon_qunzip8)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd + 1] = make_float64(d1);
 }
 
-void HELPER(neon_qunzip16)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qunzip16)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm0 = float64_val(env->vfp.regs[rm]);
     uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
@@ -1910,7 +1889,7 @@ void HELPER(neon_qunzip16)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd + 1] = make_float64(d1);
 }
 
-void HELPER(neon_qunzip32)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qunzip32)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm0 = float64_val(env->vfp.regs[rm]);
     uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
@@ -1926,7 +1905,7 @@ void HELPER(neon_qunzip32)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd + 1] = make_float64(d1);
 }
 
-void HELPER(neon_unzip8)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_unzip8)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm = float64_val(env->vfp.regs[rm]);
     uint64_t zd = float64_val(env->vfp.regs[rd]);
@@ -1942,7 +1921,7 @@ void HELPER(neon_unzip8)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd] = make_float64(d0);
 }
 
-void HELPER(neon_unzip16)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_unzip16)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm = float64_val(env->vfp.regs[rm]);
     uint64_t zd = float64_val(env->vfp.regs[rd]);
@@ -1954,7 +1933,7 @@ void HELPER(neon_unzip16)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd] = make_float64(d0);
 }
 
-void HELPER(neon_qzip8)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qzip8)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm0 = float64_val(env->vfp.regs[rm]);
     uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
@@ -1982,7 +1961,7 @@ void HELPER(neon_qzip8)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd + 1] = make_float64(d1);
 }
 
-void HELPER(neon_qzip16)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qzip16)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm0 = float64_val(env->vfp.regs[rm]);
     uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
@@ -2002,7 +1981,7 @@ void HELPER(neon_qzip16)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd + 1] = make_float64(d1);
 }
 
-void HELPER(neon_qzip32)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qzip32)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm0 = float64_val(env->vfp.regs[rm]);
     uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
@@ -2018,7 +1997,7 @@ void HELPER(neon_qzip32)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd + 1] = make_float64(d1);
 }
 
-void HELPER(neon_zip8)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_zip8)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm = float64_val(env->vfp.regs[rm]);
     uint64_t zd = float64_val(env->vfp.regs[rd]);
@@ -2034,7 +2013,7 @@ void HELPER(neon_zip8)(CPUState *env, uint32_t rd, uint32_t rm)
     env->vfp.regs[rd] = make_float64(d0);
 }
 
-void HELPER(neon_zip16)(CPUState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_zip16)(uint32_t rd, uint32_t rm)
 {
     uint64_t zm = float64_val(env->vfp.regs[rm]);
     uint64_t zd = float64_val(env->vfp.regs[rd]);
index 3de261034888326f1f0700a7c1d70ec76f667c83..8334fbcf6d987515a52b22251631b21a61f3e730 100644 (file)
@@ -17,7 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "exec.h"
-#include "helpers.h"
+#include "helper.h"
 
 #define SIGNBIT (uint32_t)0x80000000
 #define SIGNBIT64 ((uint64_t)1 << 63)
@@ -90,7 +90,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         raise_exception(env->exception_index);
index f69912f20c9153bf02ec9e3f007d706e88d8a73d..a1af436e34915cb68d62d86731ffc73a562b1ccc 100644 (file)
 #include "tcg-op.h"
 #include "qemu-log.h"
 
-#include "helpers.h"
+#include "helper.h"
 #define GEN_HELPER 1
-#include "helpers.h"
+#include "helper.h"
 
+#define ENABLE_ARCH_4T    arm_feature(env, ARM_FEATURE_V4T)
+#define ENABLE_ARCH_5     arm_feature(env, ARM_FEATURE_V5)
+/* currently all emulated v5 cores are also v5TE, so don't bother */
+#define ENABLE_ARCH_5TE   arm_feature(env, ARM_FEATURE_V5)
 #define ENABLE_ARCH_5J    0
 #define ENABLE_ARCH_6     arm_feature(env, ARM_FEATURE_V6)
 #define ENABLE_ARCH_6K   arm_feature(env, ARM_FEATURE_V6K)
@@ -125,7 +129,7 @@ void arm_translate_init(void)
 #endif
 
 #define GEN_HELPER 2
-#include "helpers.h"
+#include "helper.h"
 }
 
 static inline TCGv load_cpu_offset(int offset)
@@ -750,6 +754,20 @@ static inline void store_reg_bx(CPUState *env, DisasContext *s,
     }
 }
 
+/* Variant of store_reg which uses branch&exchange logic when storing
+ * to r15 in ARM architecture v5T and above. This is used for storing
+ * the results of a LDR/LDM/POP into r15, and corresponds to the cases
+ * in the ARM ARM which use the LoadWritePC() pseudocode function. */
+static inline void store_reg_from_load(CPUState *env, DisasContext *s,
+                                int reg, TCGv var)
+{
+    if (reg == 15 && ENABLE_ARCH_5) {
+        gen_bx(s, var);
+    } else {
+        store_reg(s, reg, var);
+    }
+}
+
 static inline TCGv gen_ld8s(TCGv addr, int index)
 {
     TCGv tmp = tcg_temp_new_i32();
@@ -1159,22 +1177,15 @@ static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
     gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \
 }
 
-#define IWMMXT_OP_ENV(name) \
-static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
-{ \
-    iwmmxt_load_reg(cpu_V1, rn); \
-    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \
-}
-
-#define IWMMXT_OP_ENV_SIZE(name) \
-IWMMXT_OP_ENV(name##b) \
-IWMMXT_OP_ENV(name##w) \
-IWMMXT_OP_ENV(name##l)
+#define IWMMXT_OP_SIZE(name) \
+IWMMXT_OP(name##b) \
+IWMMXT_OP(name##w) \
+IWMMXT_OP(name##l)
 
-#define IWMMXT_OP_ENV1(name) \
+#define IWMMXT_OP_1(name) \
 static inline void gen_op_iwmmxt_##name##_M0(void) \
 { \
-    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
+    gen_helper_iwmmxt_##name(cpu_M0, cpu_M0); \
 }
 
 IWMMXT_OP(maddsq)
@@ -1188,51 +1199,51 @@ IWMMXT_OP(muluhw)
 IWMMXT_OP(macsw)
 IWMMXT_OP(macuw)
 
-IWMMXT_OP_ENV_SIZE(unpackl)
-IWMMXT_OP_ENV_SIZE(unpackh)
-
-IWMMXT_OP_ENV1(unpacklub)
-IWMMXT_OP_ENV1(unpackluw)
-IWMMXT_OP_ENV1(unpacklul)
-IWMMXT_OP_ENV1(unpackhub)
-IWMMXT_OP_ENV1(unpackhuw)
-IWMMXT_OP_ENV1(unpackhul)
-IWMMXT_OP_ENV1(unpacklsb)
-IWMMXT_OP_ENV1(unpacklsw)
-IWMMXT_OP_ENV1(unpacklsl)
-IWMMXT_OP_ENV1(unpackhsb)
-IWMMXT_OP_ENV1(unpackhsw)
-IWMMXT_OP_ENV1(unpackhsl)
-
-IWMMXT_OP_ENV_SIZE(cmpeq)
-IWMMXT_OP_ENV_SIZE(cmpgtu)
-IWMMXT_OP_ENV_SIZE(cmpgts)
-
-IWMMXT_OP_ENV_SIZE(mins)
-IWMMXT_OP_ENV_SIZE(minu)
-IWMMXT_OP_ENV_SIZE(maxs)
-IWMMXT_OP_ENV_SIZE(maxu)
-
-IWMMXT_OP_ENV_SIZE(subn)
-IWMMXT_OP_ENV_SIZE(addn)
-IWMMXT_OP_ENV_SIZE(subu)
-IWMMXT_OP_ENV_SIZE(addu)
-IWMMXT_OP_ENV_SIZE(subs)
-IWMMXT_OP_ENV_SIZE(adds)
-
-IWMMXT_OP_ENV(avgb0)
-IWMMXT_OP_ENV(avgb1)
-IWMMXT_OP_ENV(avgw0)
-IWMMXT_OP_ENV(avgw1)
+IWMMXT_OP_SIZE(unpackl)
+IWMMXT_OP_SIZE(unpackh)
+
+IWMMXT_OP_1(unpacklub)
+IWMMXT_OP_1(unpackluw)
+IWMMXT_OP_1(unpacklul)
+IWMMXT_OP_1(unpackhub)
+IWMMXT_OP_1(unpackhuw)
+IWMMXT_OP_1(unpackhul)
+IWMMXT_OP_1(unpacklsb)
+IWMMXT_OP_1(unpacklsw)
+IWMMXT_OP_1(unpacklsl)
+IWMMXT_OP_1(unpackhsb)
+IWMMXT_OP_1(unpackhsw)
+IWMMXT_OP_1(unpackhsl)
+
+IWMMXT_OP_SIZE(cmpeq)
+IWMMXT_OP_SIZE(cmpgtu)
+IWMMXT_OP_SIZE(cmpgts)
+
+IWMMXT_OP_SIZE(mins)
+IWMMXT_OP_SIZE(minu)
+IWMMXT_OP_SIZE(maxs)
+IWMMXT_OP_SIZE(maxu)
+
+IWMMXT_OP_SIZE(subn)
+IWMMXT_OP_SIZE(addn)
+IWMMXT_OP_SIZE(subu)
+IWMMXT_OP_SIZE(addu)
+IWMMXT_OP_SIZE(subs)
+IWMMXT_OP_SIZE(adds)
+
+IWMMXT_OP(avgb0)
+IWMMXT_OP(avgb1)
+IWMMXT_OP(avgw0)
+IWMMXT_OP(avgw1)
 
 IWMMXT_OP(msadb)
 
-IWMMXT_OP_ENV(packuw)
-IWMMXT_OP_ENV(packul)
-IWMMXT_OP_ENV(packuq)
-IWMMXT_OP_ENV(packsw)
-IWMMXT_OP_ENV(packsl)
-IWMMXT_OP_ENV(packsq)
+IWMMXT_OP(packuw)
+IWMMXT_OP(packul)
+IWMMXT_OP(packuq)
+IWMMXT_OP(packsw)
+IWMMXT_OP(packsl)
+IWMMXT_OP(packsq)
 
 static void gen_op_iwmmxt_set_mup(void)
 {
@@ -1966,13 +1977,13 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         }
         switch ((insn >> 22) & 3) {
         case 1:
-            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_srlw(cpu_M0, cpu_M0, tmp);
             break;
         case 2:
-            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_srll(cpu_M0, cpu_M0, tmp);
             break;
         case 3:
-            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_srlq(cpu_M0, cpu_M0, tmp);
             break;
         }
         tcg_temp_free_i32(tmp);
@@ -1994,13 +2005,13 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         }
         switch ((insn >> 22) & 3) {
         case 1:
-            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_sraw(cpu_M0, cpu_M0, tmp);
             break;
         case 2:
-            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_sral(cpu_M0, cpu_M0, tmp);
             break;
         case 3:
-            gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_sraq(cpu_M0, cpu_M0, tmp);
             break;
         }
         tcg_temp_free_i32(tmp);
@@ -2022,13 +2033,13 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         }
         switch ((insn >> 22) & 3) {
         case 1:
-            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_sllw(cpu_M0, cpu_M0, tmp);
             break;
         case 2:
-            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_slll(cpu_M0, cpu_M0, tmp);
             break;
         case 3:
-            gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_sllq(cpu_M0, cpu_M0, tmp);
             break;
         }
         tcg_temp_free_i32(tmp);
@@ -2050,21 +2061,21 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
                 tcg_temp_free_i32(tmp);
                 return 1;
             }
-            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_rorw(cpu_M0, cpu_M0, tmp);
             break;
         case 2:
             if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
                 tcg_temp_free_i32(tmp);
                 return 1;
             }
-            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_rorl(cpu_M0, cpu_M0, tmp);
             break;
         case 3:
             if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
                 tcg_temp_free_i32(tmp);
                 return 1;
             }
-            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
+            gen_helper_iwmmxt_rorq(cpu_M0, cpu_M0, tmp);
             break;
         }
         tcg_temp_free_i32(tmp);
@@ -2198,7 +2209,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
         rd0 = (insn >> 16) & 0xf;
         gen_op_iwmmxt_movq_M0_wRn(rd0);
         tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
-        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
+        gen_helper_iwmmxt_shufh(cpu_M0, cpu_M0, tmp);
         tcg_temp_free(tmp);
         gen_op_iwmmxt_movq_wRn_M0(wrd);
         gen_op_iwmmxt_set_mup();
@@ -2648,6 +2659,28 @@ static void gen_neon_dup_high16(TCGv var)
     tcg_temp_free_i32(tmp);
 }
 
+static TCGv gen_load_and_replicate(DisasContext *s, TCGv addr, int size)
+{
+    /* Load a single Neon element and replicate into a 32 bit TCG reg */
+    TCGv tmp;
+    switch (size) {
+    case 0:
+        tmp = gen_ld8u(addr, IS_USER(s));
+        gen_neon_dup_u8(tmp, 0);
+        break;
+    case 1:
+        tmp = gen_ld16u(addr, IS_USER(s));
+        gen_neon_dup_low16(tmp);
+        break;
+    case 2:
+        tmp = gen_ld32(addr, IS_USER(s));
+        break;
+    default: /* Avoid compiler warnings.  */
+        abort();
+    }
+    return tmp;
+}
+
 /* Disassemble a VFP instruction.  Returns nonzero if an error occured
    (ie. an undefined instruction).  */
 static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
@@ -3372,7 +3405,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
     if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
         tcg_gen_goto_tb(n);
         gen_set_pc_im(dest);
-        tcg_gen_exit_tb((long)tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         gen_set_pc_im(dest);
         tcg_gen_exit_tb(0);
@@ -3421,6 +3454,10 @@ static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
 
     /* Mask out undefined bits.  */
     mask &= ~CPSR_RESERVED;
+    if (!arm_feature(env, ARM_FEATURE_V4T))
+        mask &= ~CPSR_T;
+    if (!arm_feature(env, ARM_FEATURE_V5))
+        mask &= ~CPSR_Q; /* V5TE in reality*/
     if (!arm_feature(env, ARM_FEATURE_V6))
         mask &= ~(CPSR_E | CPSR_GE);
     if (!arm_feature(env, ARM_FEATURE_THUMB2))
@@ -3521,15 +3558,14 @@ static void gen_nop_hint(DisasContext *s, int val)
 
 #define CPU_V001 cpu_V0, cpu_V0, cpu_V1
 
-static inline int gen_neon_add(int size, TCGv t0, TCGv t1)
+static inline void gen_neon_add(int size, TCGv t0, TCGv t1)
 {
     switch (size) {
     case 0: gen_helper_neon_add_u8(t0, t0, t1); break;
     case 1: gen_helper_neon_add_u16(t0, t0, t1); break;
     case 2: tcg_gen_add_i32(t0, t0, t1); break;
-    default: return 1;
+    default: abort();
     }
-    return 0;
 }
 
 static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
@@ -3626,7 +3662,7 @@ static inline TCGv neon_get_scalar(int size, int reg)
 static int gen_neon_unzip(int rd, int rm, int size, int q)
 {
     TCGv tmp, tmp2;
-    if (size == 3 || (!q && size == 2)) {
+    if (!q && size == 2) {
         return 1;
     }
     tmp = tcg_const_i32(rd);
@@ -3634,13 +3670,13 @@ static int gen_neon_unzip(int rd, int rm, int size, int q)
     if (q) {
         switch (size) {
         case 0:
-            gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
+            gen_helper_neon_qunzip8(tmp, tmp2);
             break;
         case 1:
-            gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
+            gen_helper_neon_qunzip16(tmp, tmp2);
             break;
         case 2:
-            gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
+            gen_helper_neon_qunzip32(tmp, tmp2);
             break;
         default:
             abort();
@@ -3648,10 +3684,10 @@ static int gen_neon_unzip(int rd, int rm, int size, int q)
     } else {
         switch (size) {
         case 0:
-            gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
+            gen_helper_neon_unzip8(tmp, tmp2);
             break;
         case 1:
-            gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
+            gen_helper_neon_unzip16(tmp, tmp2);
             break;
         default:
             abort();
@@ -3665,7 +3701,7 @@ static int gen_neon_unzip(int rd, int rm, int size, int q)
 static int gen_neon_zip(int rd, int rm, int size, int q)
 {
     TCGv tmp, tmp2;
-    if (size == 3 || (!q && size == 2)) {
+    if (!q && size == 2) {
         return 1;
     }
     tmp = tcg_const_i32(rd);
@@ -3673,13 +3709,13 @@ static int gen_neon_zip(int rd, int rm, int size, int q)
     if (q) {
         switch (size) {
         case 0:
-            gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
+            gen_helper_neon_qzip8(tmp, tmp2);
             break;
         case 1:
-            gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
+            gen_helper_neon_qzip16(tmp, tmp2);
             break;
         case 2:
-            gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
+            gen_helper_neon_qzip32(tmp, tmp2);
             break;
         default:
             abort();
@@ -3687,10 +3723,10 @@ static int gen_neon_zip(int rd, int rm, int size, int q)
     } else {
         switch (size) {
         case 0:
-            gen_helper_neon_zip8(cpu_env, tmp, tmp2);
+            gen_helper_neon_zip8(tmp, tmp2);
             break;
         case 1:
-            gen_helper_neon_zip16(cpu_env, tmp, tmp2);
+            gen_helper_neon_zip16(tmp, tmp2);
             break;
         default:
             abort();
@@ -3788,18 +3824,33 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
     rn = (insn >> 16) & 0xf;
     rm = insn & 0xf;
     load = (insn & (1 << 21)) != 0;
-    addr = tcg_temp_new_i32();
     if ((insn & (1 << 23)) == 0) {
         /* Load store all elements.  */
         op = (insn >> 8) & 0xf;
         size = (insn >> 6) & 3;
         if (op > 10)
             return 1;
+        /* Catch UNDEF cases for bad values of align field */
+        switch (op & 0xc) {
+        case 4:
+            if (((insn >> 5) & 1) == 1) {
+                return 1;
+            }
+            break;
+        case 8:
+            if (((insn >> 4) & 3) == 3) {
+                return 1;
+            }
+            break;
+        default:
+            break;
+        }
         nregs = neon_ls_element_type[op].nregs;
         interleave = neon_ls_element_type[op].interleave;
         spacing = neon_ls_element_type[op].spacing;
         if (size == 3 && (interleave | spacing) != 1)
             return 1;
+        addr = tcg_temp_new_i32();
         load_reg_var(s, addr, rn);
         stride = (1 << size) * interleave;
         for (reg = 0; reg < nregs; reg++) {
@@ -3885,45 +3936,61 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
             }
             rd += spacing;
         }
+        tcg_temp_free_i32(addr);
         stride = nregs * 8;
     } else {
         size = (insn >> 10) & 3;
         if (size == 3) {
             /* Load single element to all lanes.  */
-            if (!load)
+            int a = (insn >> 4) & 1;
+            if (!load) {
                 return 1;
+            }
             size = (insn >> 6) & 3;
             nregs = ((insn >> 8) & 3) + 1;
-            stride = (insn & (1 << 5)) ? 2 : 1;
-            load_reg_var(s, addr, rn);
-            for (reg = 0; reg < nregs; reg++) {
-                switch (size) {
-                case 0:
-                    tmp = gen_ld8u(addr, IS_USER(s));
-                    gen_neon_dup_u8(tmp, 0);
-                    break;
-                case 1:
-                    tmp = gen_ld16u(addr, IS_USER(s));
-                    gen_neon_dup_low16(tmp);
-                    break;
-                case 2:
-                    tmp = gen_ld32(addr, IS_USER(s));
-                    break;
-                case 3:
+
+            if (size == 3) {
+                if (nregs != 4 || a == 0) {
                     return 1;
-                default: /* Avoid compiler warnings.  */
-                    abort();
                 }
-                tcg_gen_addi_i32(addr, addr, 1 << size);
-                tmp2 = tcg_temp_new_i32();
-                tcg_gen_mov_i32(tmp2, tmp);
-                neon_store_reg(rd, 0, tmp2);
-                neon_store_reg(rd, 1, tmp);
-                rd += stride;
+                /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */
+                size = 2;
+            }
+            if (nregs == 1 && a == 1 && size == 0) {
+                return 1;
+            }
+            if (nregs == 3 && a == 1) {
+                return 1;
             }
+            addr = tcg_temp_new_i32();
+            load_reg_var(s, addr, rn);
+            if (nregs == 1) {
+                /* VLD1 to all lanes: bit 5 indicates how many Dregs to write */
+                tmp = gen_load_and_replicate(s, addr, size);
+                tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
+                tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
+                if (insn & (1 << 5)) {
+                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 0));
+                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 1));
+                }
+                tcg_temp_free_i32(tmp);
+            } else {
+                /* VLD2/3/4 to all lanes: bit 5 indicates register stride */
+                stride = (insn & (1 << 5)) ? 2 : 1;
+                for (reg = 0; reg < nregs; reg++) {
+                    tmp = gen_load_and_replicate(s, addr, size);
+                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
+                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
+                    tcg_temp_free_i32(tmp);
+                    tcg_gen_addi_i32(addr, addr, 1 << size);
+                    rd += stride;
+                }
+            }
+            tcg_temp_free_i32(addr);
             stride = (1 << size) * nregs;
         } else {
             /* Single element.  */
+            int idx = (insn >> 4) & 0xf;
             pass = (insn >> 7) & 1;
             switch (size) {
             case 0:
@@ -3942,6 +4009,40 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 abort();
             }
             nregs = ((insn >> 8) & 3) + 1;
+            /* Catch the UNDEF cases. This is unavoidably a bit messy. */
+            switch (nregs) {
+            case 1:
+                if (((idx & (1 << size)) != 0) ||
+                    (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
+                    return 1;
+                }
+                break;
+            case 3:
+                if ((idx & 1) != 0) {
+                    return 1;
+                }
+                /* fall through */
+            case 2:
+                if (size == 2 && (idx & 2) != 0) {
+                    return 1;
+                }
+                break;
+            case 4:
+                if ((size == 2) && ((idx & 3) == 3)) {
+                    return 1;
+                }
+                break;
+            default:
+                abort();
+            }
+            if ((rd + stride * (nregs - 1)) > 31) {
+                /* Attempts to write off the end of the register file
+                 * are UNPREDICTABLE; we choose to UNDEF because otherwise
+                 * the neon_load_reg() would write off the end of the array.
+                 */
+                return 1;
+            }
+            addr = tcg_temp_new_i32();
             load_reg_var(s, addr, rn);
             for (reg = 0; reg < nregs; reg++) {
                 if (load) {
@@ -3983,10 +4084,10 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 rd += stride;
                 tcg_gen_addi_i32(addr, addr, 1 << size);
             }
+            tcg_temp_free_i32(addr);
             stride = nregs * (1 << size);
         }
     }
-    tcg_temp_free_i32(addr);
     if (rm != 15) {
         TCGv base;
 
@@ -4025,9 +4126,9 @@ static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src)
 static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
 {
     switch (size) {
-    case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
-    case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break;
-    case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break;
+    case 0: gen_helper_neon_narrow_sat_s8(dest, src); break;
+    case 1: gen_helper_neon_narrow_sat_s16(dest, src); break;
+    case 2: gen_helper_neon_narrow_sat_s32(dest, src); break;
     default: abort();
     }
 }
@@ -4035,9 +4136,9 @@ static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
 static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
 {
     switch (size) {
-    case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
-    case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break;
-    case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break;
+    case 0: gen_helper_neon_narrow_sat_u8(dest, src); break;
+    case 1: gen_helper_neon_narrow_sat_u16(dest, src); break;
+    case 2: gen_helper_neon_narrow_sat_u32(dest, src); break;
     default: abort();
     }
 }
@@ -4045,9 +4146,9 @@ static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
 static inline void gen_neon_unarrow_sats(int size, TCGv dest, TCGv_i64 src)
 {
     switch (size) {
-    case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break;
-    case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break;
-    case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break;
+    case 0: gen_helper_neon_unarrow_sat8(dest, src); break;
+    case 1: gen_helper_neon_unarrow_sat16(dest, src); break;
+    case 2: gen_helper_neon_unarrow_sat32(dest, src); break;
     default: abort();
     }
 }
@@ -4139,8 +4240,8 @@ static inline void gen_neon_negl(TCGv_i64 var, int size)
 static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
 {
     switch (size) {
-    case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break;
-    case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break;
+    case 1: gen_helper_neon_addl_saturate_s32(op0, op0, op1); break;
+    case 2: gen_helper_neon_addl_saturate_s64(op0, op0, op1); break;
     default: abort();
     }
 }
@@ -4192,6 +4293,181 @@ static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src)
     }
 }
 
+/* Symbolic constants for op fields for Neon 3-register same-length.
+ * The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B
+ * table A7-9.
+ */
+#define NEON_3R_VHADD 0
+#define NEON_3R_VQADD 1
+#define NEON_3R_VRHADD 2
+#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */
+#define NEON_3R_VHSUB 4
+#define NEON_3R_VQSUB 5
+#define NEON_3R_VCGT 6
+#define NEON_3R_VCGE 7
+#define NEON_3R_VSHL 8
+#define NEON_3R_VQSHL 9
+#define NEON_3R_VRSHL 10
+#define NEON_3R_VQRSHL 11
+#define NEON_3R_VMAX 12
+#define NEON_3R_VMIN 13
+#define NEON_3R_VABD 14
+#define NEON_3R_VABA 15
+#define NEON_3R_VADD_VSUB 16
+#define NEON_3R_VTST_VCEQ 17
+#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */
+#define NEON_3R_VMUL 19
+#define NEON_3R_VPMAX 20
+#define NEON_3R_VPMIN 21
+#define NEON_3R_VQDMULH_VQRDMULH 22
+#define NEON_3R_VPADD 23
+#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */
+#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */
+#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */
+#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */
+#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */
+#define NEON_3R_VRECPS_VRSQRTS 31 /* float VRECPS, VRSQRTS */
+
+static const uint8_t neon_3r_sizes[] = {
+    [NEON_3R_VHADD] = 0x7,
+    [NEON_3R_VQADD] = 0xf,
+    [NEON_3R_VRHADD] = 0x7,
+    [NEON_3R_LOGIC] = 0xf, /* size field encodes op type */
+    [NEON_3R_VHSUB] = 0x7,
+    [NEON_3R_VQSUB] = 0xf,
+    [NEON_3R_VCGT] = 0x7,
+    [NEON_3R_VCGE] = 0x7,
+    [NEON_3R_VSHL] = 0xf,
+    [NEON_3R_VQSHL] = 0xf,
+    [NEON_3R_VRSHL] = 0xf,
+    [NEON_3R_VQRSHL] = 0xf,
+    [NEON_3R_VMAX] = 0x7,
+    [NEON_3R_VMIN] = 0x7,
+    [NEON_3R_VABD] = 0x7,
+    [NEON_3R_VABA] = 0x7,
+    [NEON_3R_VADD_VSUB] = 0xf,
+    [NEON_3R_VTST_VCEQ] = 0x7,
+    [NEON_3R_VML] = 0x7,
+    [NEON_3R_VMUL] = 0x7,
+    [NEON_3R_VPMAX] = 0x7,
+    [NEON_3R_VPMIN] = 0x7,
+    [NEON_3R_VQDMULH_VQRDMULH] = 0x6,
+    [NEON_3R_VPADD] = 0x7,
+    [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */
+    [NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */
+};
+
+/* Symbolic constants for op fields for Neon 2-register miscellaneous.
+ * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
+ * table A7-13.
+ */
+#define NEON_2RM_VREV64 0
+#define NEON_2RM_VREV32 1
+#define NEON_2RM_VREV16 2
+#define NEON_2RM_VPADDL 4
+#define NEON_2RM_VPADDL_U 5
+#define NEON_2RM_VCLS 8
+#define NEON_2RM_VCLZ 9
+#define NEON_2RM_VCNT 10
+#define NEON_2RM_VMVN 11
+#define NEON_2RM_VPADAL 12
+#define NEON_2RM_VPADAL_U 13
+#define NEON_2RM_VQABS 14
+#define NEON_2RM_VQNEG 15
+#define NEON_2RM_VCGT0 16
+#define NEON_2RM_VCGE0 17
+#define NEON_2RM_VCEQ0 18
+#define NEON_2RM_VCLE0 19
+#define NEON_2RM_VCLT0 20
+#define NEON_2RM_VABS 22
+#define NEON_2RM_VNEG 23
+#define NEON_2RM_VCGT0_F 24
+#define NEON_2RM_VCGE0_F 25
+#define NEON_2RM_VCEQ0_F 26
+#define NEON_2RM_VCLE0_F 27
+#define NEON_2RM_VCLT0_F 28
+#define NEON_2RM_VABS_F 30
+#define NEON_2RM_VNEG_F 31
+#define NEON_2RM_VSWP 32
+#define NEON_2RM_VTRN 33
+#define NEON_2RM_VUZP 34
+#define NEON_2RM_VZIP 35
+#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */
+#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */
+#define NEON_2RM_VSHLL 38
+#define NEON_2RM_VCVT_F16_F32 44
+#define NEON_2RM_VCVT_F32_F16 46
+#define NEON_2RM_VRECPE 56
+#define NEON_2RM_VRSQRTE 57
+#define NEON_2RM_VRECPE_F 58
+#define NEON_2RM_VRSQRTE_F 59
+#define NEON_2RM_VCVT_FS 60
+#define NEON_2RM_VCVT_FU 61
+#define NEON_2RM_VCVT_SF 62
+#define NEON_2RM_VCVT_UF 63
+
+static int neon_2rm_is_float_op(int op)
+{
+    /* Return true if this neon 2reg-misc op is float-to-float */
+    return (op == NEON_2RM_VABS_F || op == NEON_2RM_VNEG_F ||
+            op >= NEON_2RM_VRECPE_F);
+}
+
+/* Each entry in this array has bit n set if the insn allows
+ * size value n (otherwise it will UNDEF). Since unallocated
+ * op values will have no bits set they always UNDEF.
+ */
+static const uint8_t neon_2rm_sizes[] = {
+    [NEON_2RM_VREV64] = 0x7,
+    [NEON_2RM_VREV32] = 0x3,
+    [NEON_2RM_VREV16] = 0x1,
+    [NEON_2RM_VPADDL] = 0x7,
+    [NEON_2RM_VPADDL_U] = 0x7,
+    [NEON_2RM_VCLS] = 0x7,
+    [NEON_2RM_VCLZ] = 0x7,
+    [NEON_2RM_VCNT] = 0x1,
+    [NEON_2RM_VMVN] = 0x1,
+    [NEON_2RM_VPADAL] = 0x7,
+    [NEON_2RM_VPADAL_U] = 0x7,
+    [NEON_2RM_VQABS] = 0x7,
+    [NEON_2RM_VQNEG] = 0x7,
+    [NEON_2RM_VCGT0] = 0x7,
+    [NEON_2RM_VCGE0] = 0x7,
+    [NEON_2RM_VCEQ0] = 0x7,
+    [NEON_2RM_VCLE0] = 0x7,
+    [NEON_2RM_VCLT0] = 0x7,
+    [NEON_2RM_VABS] = 0x7,
+    [NEON_2RM_VNEG] = 0x7,
+    [NEON_2RM_VCGT0_F] = 0x4,
+    [NEON_2RM_VCGE0_F] = 0x4,
+    [NEON_2RM_VCEQ0_F] = 0x4,
+    [NEON_2RM_VCLE0_F] = 0x4,
+    [NEON_2RM_VCLT0_F] = 0x4,
+    [NEON_2RM_VABS_F] = 0x4,
+    [NEON_2RM_VNEG_F] = 0x4,
+    [NEON_2RM_VSWP] = 0x1,
+    [NEON_2RM_VTRN] = 0x7,
+    [NEON_2RM_VUZP] = 0x7,
+    [NEON_2RM_VZIP] = 0x7,
+    [NEON_2RM_VMOVN] = 0x7,
+    [NEON_2RM_VQMOVN] = 0x7,
+    [NEON_2RM_VSHLL] = 0x7,
+    [NEON_2RM_VCVT_F16_F32] = 0x2,
+    [NEON_2RM_VCVT_F32_F16] = 0x2,
+    [NEON_2RM_VRECPE] = 0x4,
+    [NEON_2RM_VRSQRTE] = 0x4,
+    [NEON_2RM_VRECPE_F] = 0x4,
+    [NEON_2RM_VRSQRTE_F] = 0x4,
+    [NEON_2RM_VCVT_FS] = 0x4,
+    [NEON_2RM_VCVT_FU] = 0x4,
+    [NEON_2RM_VCVT_SF] = 0x4,
+    [NEON_2RM_VCVT_UF] = 0x4,
+};
+
 /* Translate a NEON data processing instruction.  Return nonzero if the
    instruction is invalid.
    We process data in a mixture of 32-bit and 64-bit chunks.
@@ -4208,7 +4484,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
     int count;
     int pairwise;
     int u;
-    int n;
     uint32_t imm, mask;
     TCGv tmp, tmp2, tmp3, tmp4, tmp5;
     TCGv_i64 tmp64;
@@ -4224,64 +4499,65 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
     if ((insn & (1 << 23)) == 0) {
         /* Three register same length.  */
         op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
-        if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9
-                          || op == 10 || op  == 11 || op == 16)) {
-            /* 64-bit element instructions.  */
+        /* Catch invalid op and bad size combinations: UNDEF */
+        if ((neon_3r_sizes[op] & (1 << size)) == 0) {
+            return 1;
+        }
+        /* All insns of this form UNDEF for either this condition or the
+         * superset of cases "Q==1"; we catch the latter later.
+         */
+        if (q && ((rd | rn | rm) & 1)) {
+            return 1;
+        }
+        if (size == 3 && op != NEON_3R_LOGIC) {
+            /* 64-bit element instructions. */
             for (pass = 0; pass < (q ? 2 : 1); pass++) {
                 neon_load_reg64(cpu_V0, rn + pass);
                 neon_load_reg64(cpu_V1, rm + pass);
                 switch (op) {
-                case 1: /* VQADD */
+                case NEON_3R_VQADD:
                     if (u) {
-                        gen_helper_neon_qadd_u64(cpu_V0, cpu_env,
-                                                 cpu_V0, cpu_V1);
+                        gen_helper_neon_qadd_u64(cpu_V0, cpu_V0, cpu_V1);
                     } else {
-                        gen_helper_neon_qadd_s64(cpu_V0, cpu_env,
-                                                 cpu_V0, cpu_V1);
+                        gen_helper_neon_qadd_s64(cpu_V0, cpu_V0, cpu_V1);
                     }
                     break;
-                case 5: /* VQSUB */
+                case NEON_3R_VQSUB:
                     if (u) {
-                        gen_helper_neon_qsub_u64(cpu_V0, cpu_env,
-                                                 cpu_V0, cpu_V1);
+                        gen_helper_neon_qsub_u64(cpu_V0, cpu_V0, cpu_V1);
                     } else {
-                        gen_helper_neon_qsub_s64(cpu_V0, cpu_env,
-                                                 cpu_V0, cpu_V1);
+                        gen_helper_neon_qsub_s64(cpu_V0, cpu_V0, cpu_V1);
                     }
                     break;
-                case 8: /* VSHL */
+                case NEON_3R_VSHL:
                     if (u) {
                         gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
                     } else {
                         gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
                     }
                     break;
-                case 9: /* VQSHL */
+                case NEON_3R_VQSHL:
                     if (u) {
-                        gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
-                                                 cpu_V1, cpu_V0);
+                        gen_helper_neon_qshl_u64(cpu_V0, cpu_V1, cpu_V0);
                     } else {
-                        gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
-                                                 cpu_V1, cpu_V0);
+                        gen_helper_neon_qshl_s64(cpu_V0, cpu_V1, cpu_V0);
                     }
                     break;
-                case 10: /* VRSHL */
+                case NEON_3R_VRSHL:
                     if (u) {
                         gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
                     } else {
                         gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
                     }
                     break;
-                case 11: /* VQRSHL */
+                case NEON_3R_VQRSHL:
                     if (u) {
-                        gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
-                                                  cpu_V1, cpu_V0);
+                        gen_helper_neon_qrshl_u64(cpu_V0, cpu_V1, cpu_V0);
                     } else {
-                        gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
-                                                  cpu_V1, cpu_V0);
+                        gen_helper_neon_qrshl_s64(cpu_V0, cpu_V1, cpu_V0);
                     }
                     break;
-                case 16:
+                case NEON_3R_VADD_VSUB:
                     if (u) {
                         tcg_gen_sub_i64(CPU_V001);
                     } else {
@@ -4295,50 +4571,76 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
             }
             return 0;
         }
+        pairwise = 0;
         switch (op) {
-        case 8: /* VSHL */
-        case 9: /* VQSHL */
-        case 10: /* VRSHL */
-        case 11: /* VQRSHL */
+        case NEON_3R_VSHL:
+        case NEON_3R_VQSHL:
+        case NEON_3R_VRSHL:
+        case NEON_3R_VQRSHL:
             {
                 int rtmp;
                 /* Shift instruction operands are reversed.  */
                 rtmp = rn;
                 rn = rm;
                 rm = rtmp;
-                pairwise = 0;
             }
             break;
-        case 20: /* VPMAX */
-        case 21: /* VPMIN */
-        case 23: /* VPADD */
+        case NEON_3R_VPADD:
+            if (u) {
+                return 1;
+            }
+            /* Fall through */
+        case NEON_3R_VPMAX:
+        case NEON_3R_VPMIN:
             pairwise = 1;
             break;
-        case 26: /* VPADD (float) */
-            pairwise = (u && size < 2);
+        case NEON_3R_FLOAT_ARITH:
+            pairwise = (u && size < 2); /* if VPADD (float) */
+            break;
+        case NEON_3R_FLOAT_MINMAX:
+            pairwise = u; /* if VPMIN/VPMAX (float) */
             break;
-        case 30: /* VPMIN/VPMAX (float) */
-            pairwise = u;
+        case NEON_3R_FLOAT_CMP:
+            if (!u && size) {
+                /* no encoding for U=0 C=1x */
+                return 1;
+            }
+            break;
+        case NEON_3R_FLOAT_ACMP:
+            if (!u) {
+                return 1;
+            }
+            break;
+        case NEON_3R_VRECPS_VRSQRTS:
+            if (u) {
+                return 1;
+            }
+            break;
+        case NEON_3R_VMUL:
+            if (u && (size != 0)) {
+                /* UNDEF on invalid size for polynomial subcase */
+                return 1;
+            }
             break;
         default:
-            pairwise = 0;
             break;
         }
 
+        if (pairwise && q) {
+            /* All the pairwise insns UNDEF if Q is set */
+            return 1;
+        }
+
         for (pass = 0; pass < (q ? 4 : 2); pass++) {
 
         if (pairwise) {
             /* Pairwise.  */
-            if (q)
-                n = (pass & 1) * 2;
-            else
-                n = 0;
-            if (pass < q + 1) {
-                tmp = neon_load_reg(rn, n);
-                tmp2 = neon_load_reg(rn, n + 1);
+            if (pass < 1) {
+                tmp = neon_load_reg(rn, 0);
+                tmp2 = neon_load_reg(rn, 1);
             } else {
-                tmp = neon_load_reg(rm, n);
-                tmp2 = neon_load_reg(rm, n + 1);
+                tmp = neon_load_reg(rm, 0);
+                tmp2 = neon_load_reg(rm, 1);
             }
         } else {
             /* Elementwise.  */
@@ -4346,16 +4648,16 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
             tmp2 = neon_load_reg(rm, pass);
         }
         switch (op) {
-        case 0: /* VHADD */
+        case NEON_3R_VHADD:
             GEN_NEON_INTEGER_OP(hadd);
             break;
-        case 1: /* VQADD */
-            GEN_NEON_INTEGER_OP_ENV(qadd);
+        case NEON_3R_VQADD:
+            GEN_NEON_INTEGER_OP(qadd);
             break;
-        case 2: /* VRHADD */
+        case NEON_3R_VRHADD:
             GEN_NEON_INTEGER_OP(rhadd);
             break;
-        case 3: /* Logic ops.  */
+        case NEON_3R_LOGIC: /* Logic ops.  */
             switch ((u << 2) | size) {
             case 0: /* VAND */
                 tcg_gen_and_i32(tmp, tmp, tmp2);
@@ -4389,81 +4691,80 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 break;
             }
             break;
-        case 4: /* VHSUB */
+        case NEON_3R_VHSUB:
             GEN_NEON_INTEGER_OP(hsub);
             break;
-        case 5: /* VQSUB */
-            GEN_NEON_INTEGER_OP_ENV(qsub);
+        case NEON_3R_VQSUB:
+            GEN_NEON_INTEGER_OP(qsub);
             break;
-        case 6: /* VCGT */
+        case NEON_3R_VCGT:
             GEN_NEON_INTEGER_OP(cgt);
             break;
-        case 7: /* VCGE */
+        case NEON_3R_VCGE:
             GEN_NEON_INTEGER_OP(cge);
             break;
-        case 8: /* VSHL */
+        case NEON_3R_VSHL:
             GEN_NEON_INTEGER_OP(shl);
             break;
-        case 9: /* VQSHL */
-            GEN_NEON_INTEGER_OP_ENV(qshl);
+        case NEON_3R_VQSHL:
+            GEN_NEON_INTEGER_OP(qshl);
             break;
-        case 10: /* VRSHL */
+        case NEON_3R_VRSHL:
             GEN_NEON_INTEGER_OP(rshl);
             break;
-        case 11: /* VQRSHL */
-            GEN_NEON_INTEGER_OP_ENV(qrshl);
+        case NEON_3R_VQRSHL:
+            GEN_NEON_INTEGER_OP(qrshl);
             break;
-        case 12: /* VMAX */
+        case NEON_3R_VMAX:
             GEN_NEON_INTEGER_OP(max);
             break;
-        case 13: /* VMIN */
+        case NEON_3R_VMIN:
             GEN_NEON_INTEGER_OP(min);
             break;
-        case 14: /* VABD */
+        case NEON_3R_VABD:
             GEN_NEON_INTEGER_OP(abd);
             break;
-        case 15: /* VABA */
+        case NEON_3R_VABA:
             GEN_NEON_INTEGER_OP(abd);
             tcg_temp_free_i32(tmp2);
             tmp2 = neon_load_reg(rd, pass);
             gen_neon_add(size, tmp, tmp2);
             break;
-        case 16:
+        case NEON_3R_VADD_VSUB:
             if (!u) { /* VADD */
-                if (gen_neon_add(size, tmp, tmp2))
-                    return 1;
+                gen_neon_add(size, tmp, tmp2);
             } else { /* VSUB */
                 switch (size) {
                 case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
                 case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
                 case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
-                default: return 1;
+                default: abort();
                 }
             }
             break;
-        case 17:
+        case NEON_3R_VTST_VCEQ:
             if (!u) { /* VTST */
                 switch (size) {
                 case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
                 case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
                 case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
-                default: return 1;
+                default: abort();
                 }
             } else { /* VCEQ */
                 switch (size) {
                 case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
                 case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
                 case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
-                default: return 1;
+                default: abort();
                 }
             }
             break;
-        case 18: /* Multiply.  */
+        case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */
             switch (size) {
             case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
             case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
             case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
-            default: return 1;
+            default: abort();
             }
             tcg_temp_free_i32(tmp2);
             tmp2 = neon_load_reg(rd, pass);
@@ -4473,7 +4774,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 gen_neon_add(size, tmp, tmp2);
             }
             break;
-        case 19: /* VMUL */
+        case NEON_3R_VMUL:
             if (u) { /* polynomial */
                 gen_helper_neon_mul_p8(tmp, tmp, tmp2);
             } else { /* Integer */
@@ -4481,42 +4782,40 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
                 case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
                 case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
-                default: return 1;
+                default: abort();
                 }
             }
             break;
-        case 20: /* VPMAX */
+        case NEON_3R_VPMAX:
             GEN_NEON_INTEGER_OP(pmax);
             break;
-        case 21: /* VPMIN */
+        case NEON_3R_VPMIN:
             GEN_NEON_INTEGER_OP(pmin);
             break;
-        case 22: /* Hultiply high.  */
+        case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high.  */
             if (!u) { /* VQDMULH */
                 switch (size) {
-                case 1: gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); break;
-                case 2: gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); break;
-                default: return 1;
+                case 1: gen_helper_neon_qdmulh_s16(tmp, tmp, tmp2); break;
+                case 2: gen_helper_neon_qdmulh_s32(tmp, tmp, tmp2); break;
+                default: abort();
                 }
-            } else { /* VQRDHMUL */
+            } else { /* VQRDMULH */
                 switch (size) {
-                case 1: gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); break;
-                case 2: gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); break;
-                default: return 1;
+                case 1: gen_helper_neon_qrdmulh_s16(tmp, tmp, tmp2); break;
+                case 2: gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2); break;
+                default: abort();
                 }
             }
             break;
-        case 23: /* VPADD */
-            if (u)
-                return 1;
+        case NEON_3R_VPADD:
             switch (size) {
             case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
             case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
             case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
-            default: return 1;
+            default: abort();
             }
             break;
-        case 26: /* Floating point arithnetic.  */
+        case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
             switch ((u << 2) | size) {
             case 0: /* VADD */
                 gen_helper_neon_add_f32(tmp, tmp, tmp2);
@@ -4531,10 +4830,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 gen_helper_neon_abd_f32(tmp, tmp, tmp2);
                 break;
             default:
-                return 1;
+                abort();
             }
             break;
-        case 27: /* Float multiply.  */
+        case NEON_3R_FLOAT_MULTIPLY:
             gen_helper_neon_mul_f32(tmp, tmp, tmp2);
             if (!u) {
                 tcg_temp_free_i32(tmp2);
@@ -4546,7 +4845,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 }
             }
             break;
-        case 28: /* Float compare.  */
+        case NEON_3R_FLOAT_CMP:
             if (!u) {
                 gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
             } else {
@@ -4556,21 +4855,19 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
             }
             break;
-        case 29: /* Float compare absolute.  */
-            if (!u)
-                return 1;
+        case NEON_3R_FLOAT_ACMP:
             if (size == 0)
                 gen_helper_neon_acge_f32(tmp, tmp, tmp2);
             else
                 gen_helper_neon_acgt_f32(tmp, tmp, tmp2);
             break;
-        case 30: /* Float min/max.  */
+        case NEON_3R_FLOAT_MINMAX:
             if (size == 0)
                 gen_helper_neon_max_f32(tmp, tmp, tmp2);
             else
                 gen_helper_neon_min_f32(tmp, tmp, tmp2);
             break;
-        case 31:
+        case NEON_3R_VRECPS_VRSQRTS:
             if (size == 0)
                 gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
             else
@@ -4603,7 +4900,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
             /* Two registers and shift.  */
             op = (insn >> 8) & 0xf;
             if (insn & (1 << 7)) {
-                /* 64-bit shift.   */
+                /* 64-bit shift. */
+                if (op > 7) {
+                    return 1;
+                }
                 size = 3;
             } else {
                 size = 2;
@@ -4616,6 +4916,12 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
             if (op < 8) {
                 /* Shift by immediate:
                    VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU.  */
+                if (q && ((rd | rm) & 1)) {
+                    return 1;
+                }
+                if (!u && (op == 4 || op == 6)) {
+                    return 1;
+                }
                 /* Right shifts are encoded as N - shift, where N is the
                    element size in bits.  */
                 if (op <= 4)
@@ -4663,27 +4969,18 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                                 gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
                             break;
                         case 4: /* VSRI */
-                            if (!u)
-                                return 1;
-                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
-                            break;
                         case 5: /* VSHL, VSLI */
                             gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
                             break;
                         case 6: /* VQSHLU */
-                            if (u) {
-                                gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
-                                                          cpu_V0, cpu_V1);
-                            } else {
-                                return 1;
-                            }
+                            gen_helper_neon_qshlu_s64(cpu_V0, cpu_V0, cpu_V1);
                             break;
                         case 7: /* VQSHL */
                             if (u) {
-                                gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
+                                gen_helper_neon_qshl_u64(cpu_V0,
                                                          cpu_V0, cpu_V1);
                             } else {
-                                gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
+                                gen_helper_neon_qshl_s64(cpu_V0,
                                                          cpu_V0, cpu_V1);
                             }
                             break;
@@ -4724,41 +5021,31 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             GEN_NEON_INTEGER_OP(rshl);
                             break;
                         case 4: /* VSRI */
-                            if (!u)
-                                return 1;
-                            GEN_NEON_INTEGER_OP(shl);
-                            break;
                         case 5: /* VSHL, VSLI */
                             switch (size) {
                             case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break;
                             case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break;
                             case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break;
-                            default: return 1;
+                            default: abort();
                             }
                             break;
                         case 6: /* VQSHLU */
-                            if (!u) {
-                                return 1;
-                            }
                             switch (size) {
                             case 0:
-                                gen_helper_neon_qshlu_s8(tmp, cpu_env,
-                                                         tmp, tmp2);
+                                gen_helper_neon_qshlu_s8(tmp, tmp, tmp2);
                                 break;
                             case 1:
-                                gen_helper_neon_qshlu_s16(tmp, cpu_env,
-                                                          tmp, tmp2);
+                                gen_helper_neon_qshlu_s16(tmp, tmp, tmp2);
                                 break;
                             case 2:
-                                gen_helper_neon_qshlu_s32(tmp, cpu_env,
-                                                          tmp, tmp2);
+                                gen_helper_neon_qshlu_s32(tmp, tmp, tmp2);
                                 break;
                             default:
-                                return 1;
+                                abort();
                             }
                             break;
                         case 7: /* VQSHL */
-                            GEN_NEON_INTEGER_OP_ENV(qshl);
+                            GEN_NEON_INTEGER_OP(qshl);
                             break;
                         }
                         tcg_temp_free_i32(tmp2);
@@ -4812,7 +5099,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 /* Shift by immediate and narrow:
                    VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */
                 int input_unsigned = (op == 8) ? !u : u;
-
+                if (rm & 1) {
+                    return 1;
+                }
                 shift = shift - (1 << (size + 3));
                 size++;
                 if (size == 3) {
@@ -4880,9 +5169,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     tcg_temp_free_i32(tmp2);
                 }
             } else if (op == 10) {
-                /* VSHLL */
-                if (q || size == 3)
+                /* VSHLL, VMOVL */
+                if (q || (rd & 1)) {
                     return 1;
+                }
                 tmp = neon_load_reg(rm, 0);
                 tmp2 = neon_load_reg(rm, 1);
                 for (pass = 0; pass < 2; pass++) {
@@ -4923,6 +5213,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 }
             } else if (op >= 14) {
                 /* VCVT fixed-point.  */
+                if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
+                    return 1;
+                }
                 /* We have already masked out the must-be-1 top bit of imm6,
                  * hence this 32-shift where the ARM ARM has 64-imm6.
                  */
@@ -4947,11 +5240,18 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
             }
         } else { /* (insn & 0x00380080) == 0 */
             int invert;
+            if (q && (rd & 1)) {
+                return 1;
+            }
 
             op = (insn >> 8) & 0xf;
             /* One register and immediate.  */
             imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
             invert = (insn & (1 << 5)) != 0;
+            /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
+             * We choose to not special-case this and will behave as if a
+             * valid constant encoding of 0 had been given.
+             */
             switch (op) {
             case 0: case 1:
                 /* no-op */
@@ -4983,6 +5283,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     imm = ~imm;
                 break;
             case 15:
+                if (invert) {
+                    return 1;
+                }
                 imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
                       | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
                 break;
@@ -5004,6 +5307,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     /* VMOV, VMVN.  */
                     tmp = tcg_temp_new_i32();
                     if (op == 14 && invert) {
+                        int n;
                         uint32_t val;
                         val = 0;
                         for (n = 0; n < 4; n++) {
@@ -5026,31 +5330,47 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 int src1_wide;
                 int src2_wide;
                 int prewiden;
-                /* prewiden, src1_wide, src2_wide */
-                static const int neon_3reg_wide[16][3] = {
-                    {1, 0, 0}, /* VADDL */
-                    {1, 1, 0}, /* VADDW */
-                    {1, 0, 0}, /* VSUBL */
-                    {1, 1, 0}, /* VSUBW */
-                    {0, 1, 1}, /* VADDHN */
-                    {0, 0, 0}, /* VABAL */
-                    {0, 1, 1}, /* VSUBHN */
-                    {0, 0, 0}, /* VABDL */
-                    {0, 0, 0}, /* VMLAL */
-                    {0, 0, 0}, /* VQDMLAL */
-                    {0, 0, 0}, /* VMLSL */
-                    {0, 0, 0}, /* VQDMLSL */
-                    {0, 0, 0}, /* Integer VMULL */
-                    {0, 0, 0}, /* VQDMULL */
-                    {0, 0, 0}  /* Polynomial VMULL */
+                /* undefreq: bit 0 : UNDEF if size != 0
+                 *           bit 1 : UNDEF if size == 0
+                 *           bit 2 : UNDEF if U == 1
+                 * Note that [1:0] set implies 'always UNDEF'
+                 */
+                int undefreq;
+                /* prewiden, src1_wide, src2_wide, undefreq */
+                static const int neon_3reg_wide[16][4] = {
+                    {1, 0, 0, 0}, /* VADDL */
+                    {1, 1, 0, 0}, /* VADDW */
+                    {1, 0, 0, 0}, /* VSUBL */
+                    {1, 1, 0, 0}, /* VSUBW */
+                    {0, 1, 1, 0}, /* VADDHN */
+                    {0, 0, 0, 0}, /* VABAL */
+                    {0, 1, 1, 0}, /* VSUBHN */
+                    {0, 0, 0, 0}, /* VABDL */
+                    {0, 0, 0, 0}, /* VMLAL */
+                    {0, 0, 0, 6}, /* VQDMLAL */
+                    {0, 0, 0, 0}, /* VMLSL */
+                    {0, 0, 0, 6}, /* VQDMLSL */
+                    {0, 0, 0, 0}, /* Integer VMULL */
+                    {0, 0, 0, 2}, /* VQDMULL */
+                    {0, 0, 0, 5}, /* Polynomial VMULL */
+                    {0, 0, 0, 3}, /* Reserved: always UNDEF */
                 };
 
                 prewiden = neon_3reg_wide[op][0];
                 src1_wide = neon_3reg_wide[op][1];
                 src2_wide = neon_3reg_wide[op][2];
+                undefreq = neon_3reg_wide[op][3];
 
-                if (size == 0 && (op == 9 || op == 11 || op == 13))
+                if (((undefreq & 1) && (size != 0)) ||
+                    ((undefreq & 2) && (size == 0)) ||
+                    ((undefreq & 4) && u)) {
+                    return 1;
+                }
+                if ((src1_wide && (rn & 1)) ||
+                    (src2_wide && (rm & 1)) ||
+                    (!src2_wide && (rd & 1))) {
                     return 1;
+                }
 
                 /* Avoid overlapping operands.  Wide source operands are
                    always aligned so will never overlap with wide
@@ -5131,8 +5451,8 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         tcg_temp_free_i32(tmp2);
                         tcg_temp_free_i32(tmp);
                         break;
-                    default: /* 15 is RESERVED.  */
-                        return 1;
+                    default: /* 15 is RESERVED: caught earlier  */
+                        abort();
                     }
                     if (op == 13) {
                         /* VQDMULL */
@@ -5204,16 +5524,29 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     }
                 }
             } else {
-                /* Two registers and a scalar.  */
+                /* Two registers and a scalar. NB that for ops of this form
+                 * the ARM ARM labels bit 24 as Q, but it is in our variable
+                 * 'u', not 'q'.
+                 */
+                if (size == 0) {
+                    return 1;
+                }
                 switch (op) {
-                case 0: /* Integer VMLA scalar */
                 case 1: /* Float VMLA scalar */
-                case 4: /* Integer VMLS scalar */
                 case 5: /* Floating point VMLS scalar */
-                case 8: /* Integer VMUL scalar */
                 case 9: /* Floating point VMUL scalar */
+                    if (size == 1) {
+                        return 1;
+                    }
+                    /* fall through */
+                case 0: /* Integer VMLA scalar */
+                case 4: /* Integer VMLS scalar */
+                case 8: /* Integer VMUL scalar */
                 case 12: /* VQDMULH scalar */
                 case 13: /* VQRDMULH scalar */
+                    if (u && ((rd | rn) & 1)) {
+                        return 1;
+                    }
                     tmp = neon_get_scalar(size, rm);
                     neon_store_scratch(0, tmp);
                     for (pass = 0; pass < (u ? 4 : 2); pass++) {
@@ -5221,15 +5554,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         tmp2 = neon_load_reg(rn, pass);
                         if (op == 12) {
                             if (size == 1) {
-                                gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
+                                gen_helper_neon_qdmulh_s16(tmp, tmp, tmp2);
                             } else {
-                                gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
+                                gen_helper_neon_qdmulh_s32(tmp, tmp, tmp2);
                             }
                         } else if (op == 13) {
                             if (size == 1) {
-                                gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
+                                gen_helper_neon_qrdmulh_s16(tmp, tmp, tmp2);
                             } else {
-                                gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
+                                gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2);
                             }
                         } else if (op & 1) {
                             gen_helper_neon_mul_f32(tmp, tmp, tmp2);
@@ -5238,7 +5571,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
                             case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
                             case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
-                            default: return 1;
+                            default: abort();
                             }
                         }
                         tcg_temp_free_i32(tmp2);
@@ -5266,15 +5599,19 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         neon_store_reg(rd, pass, tmp);
                     }
                     break;
-                case 2: /* VMLAL sclar */
                 case 3: /* VQDMLAL scalar */
-                case 6: /* VMLSL scalar */
                 case 7: /* VQDMLSL scalar */
-                case 10: /* VMULL scalar */
                 case 11: /* VQDMULL scalar */
-                    if (size == 0 && (op == 3 || op == 7 || op == 11))
+                    if (u == 1) {
                         return 1;
-
+                    }
+                    /* fall through */
+                case 2: /* VMLAL sclar */
+                case 6: /* VMLSL scalar */
+                case 10: /* VMULL scalar */
+                    if (rd & 1) {
+                        return 1;
+                    }
                     tmp2 = neon_get_scalar(size, rm);
                     /* We need a copy of tmp2 because gen_neon_mull
                      * deletes it during pass 0.  */
@@ -5333,6 +5670,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 if (imm > 7 && !q)
                     return 1;
 
+                if (q && ((rd | rn | rm) & 1)) {
+                    return 1;
+                }
+
                 if (imm == 0) {
                     neon_load_reg64(cpu_V0, rn);
                     if (q) {
@@ -5381,10 +5722,16 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 /* Two register misc.  */
                 op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
                 size = (insn >> 18) & 3;
+                /* UNDEF for unknown op values and bad op-size combinations */
+                if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
+                    return 1;
+                }
+                if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
+                    q && ((rm | rd) & 1)) {
+                    return 1;
+                }
                 switch (op) {
-                case 0: /* VREV64 */
-                    if (size == 3)
-                        return 1;
+                case NEON_2RM_VREV64:
                     for (pass = 0; pass < (q ? 2 : 1); pass++) {
                         tmp = neon_load_reg(rm, pass * 2);
                         tmp2 = neon_load_reg(rm, pass * 2 + 1);
@@ -5407,10 +5754,8 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         }
                     }
                     break;
-                case 4: case 5: /* VPADDL */
-                case 12: case 13: /* VPADAL */
-                    if (size == 3)
-                        return 1;
+                case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
+                case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
                     for (pass = 0; pass < q + 1; pass++) {
                         tmp = neon_load_reg(rm, pass * 2);
                         gen_neon_widen(cpu_V0, tmp, size, op & 1);
@@ -5422,7 +5767,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         case 2: tcg_gen_add_i64(CPU_V001); break;
                         default: abort();
                         }
-                        if (op >= 12) {
+                        if (op >= NEON_2RM_VPADAL) {
                             /* Accumulate.  */
                             neon_load_reg64(cpu_V1, rd + pass);
                             gen_neon_addl(size);
@@ -5430,8 +5775,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         neon_store_reg64(cpu_V0, rd + pass);
                     }
                     break;
-                case 33: /* VTRN */
+                case NEON_2RM_VTRN:
                     if (size == 2) {
+                        int n;
                         for (n = 0; n < (q ? 4 : 2); n += 2) {
                             tmp = neon_load_reg(rm, n);
                             tmp2 = neon_load_reg(rd, n + 1);
@@ -5442,24 +5788,27 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         goto elementwise;
                     }
                     break;
-                case 34: /* VUZP */
+                case NEON_2RM_VUZP:
                     if (gen_neon_unzip(rd, rm, size, q)) {
                         return 1;
                     }
                     break;
-                case 35: /* VZIP */
+                case NEON_2RM_VZIP:
                     if (gen_neon_zip(rd, rm, size, q)) {
                         return 1;
                     }
                     break;
-                case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */
-                    if (size == 3)
+                case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
+                    /* also VQMOVUN; op field and mnemonics don't line up */
+                    if (rm & 1) {
                         return 1;
+                    }
                     TCGV_UNUSED(tmp2);
                     for (pass = 0; pass < 2; pass++) {
                         neon_load_reg64(cpu_V0, rm + pass);
                         tmp = tcg_temp_new_i32();
-                        gen_neon_narrow_op(op == 36, q, size, tmp, cpu_V0);
+                        gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
+                                           tmp, cpu_V0);
                         if (pass == 0) {
                             tmp2 = tmp;
                         } else {
@@ -5468,9 +5817,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         }
                     }
                     break;
-                case 38: /* VSHLL */
-                    if (q || size == 3)
+                case NEON_2RM_VSHLL:
+                    if (q || (rd & 1)) {
                         return 1;
+                    }
                     tmp = neon_load_reg(rm, 0);
                     tmp2 = neon_load_reg(rm, 1);
                     for (pass = 0; pass < 2; pass++) {
@@ -5481,9 +5831,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         neon_store_reg64(cpu_V0, rd + pass);
                     }
                     break;
-                case 44: /* VCVT.F16.F32 */
-                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                      return 1;
+                case NEON_2RM_VCVT_F16_F32:
+                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
+                        q || (rm & 1)) {
+                        return 1;
+                    }
                     tmp = tcg_temp_new_i32();
                     tmp2 = tcg_temp_new_i32();
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
@@ -5503,9 +5855,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     neon_store_reg(rd, 1, tmp2);
                     tcg_temp_free_i32(tmp);
                     break;
-                case 46: /* VCVT.F32.F16 */
-                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                      return 1;
+                case NEON_2RM_VCVT_F32_F16:
+                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
+                        q || (rd & 1)) {
+                        return 1;
+                    }
                     tmp3 = tcg_temp_new_i32();
                     tmp = neon_load_reg(rm, 0);
                     tmp2 = neon_load_reg(rm, 1);
@@ -5528,7 +5882,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 default:
                 elementwise:
                     for (pass = 0; pass < (q ? 4 : 2); pass++) {
-                        if (op == 30 || op == 31 || op >= 58) {
+                        if (neon_2rm_is_float_op(op)) {
                             tcg_gen_ld_f32(cpu_F0s, cpu_env,
                                            neon_reg_offset(rm, pass));
                             TCGV_UNUSED(tmp);
@@ -5536,177 +5890,178 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             tmp = neon_load_reg(rm, pass);
                         }
                         switch (op) {
-                        case 1: /* VREV32 */
+                        case NEON_2RM_VREV32:
                             switch (size) {
                             case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                             case 1: gen_swap_half(tmp); break;
-                            default: return 1;
+                            default: abort();
                             }
                             break;
-                        case 2: /* VREV16 */
-                            if (size != 0)
-                                return 1;
+                        case NEON_2RM_VREV16:
                             gen_rev16(tmp);
                             break;
-                        case 8: /* CLS */
+                        case NEON_2RM_VCLS:
                             switch (size) {
                             case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
                             case 1: gen_helper_neon_cls_s16(tmp, tmp); break;
                             case 2: gen_helper_neon_cls_s32(tmp, tmp); break;
-                            default: return 1;
+                            default: abort();
                             }
                             break;
-                        case 9: /* CLZ */
+                        case NEON_2RM_VCLZ:
                             switch (size) {
                             case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
                             case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
                             case 2: gen_helper_clz(tmp, tmp); break;
-                            default: return 1;
+                            default: abort();
                             }
                             break;
-                        case 10: /* CNT */
-                            if (size != 0)
-                                return 1;
+                        case NEON_2RM_VCNT:
                             gen_helper_neon_cnt_u8(tmp, tmp);
                             break;
-                        case 11: /* VNOT */
-                            if (size != 0)
-                                return 1;
+                        case NEON_2RM_VMVN:
                             tcg_gen_not_i32(tmp, tmp);
                             break;
-                        case 14: /* VQABS */
+                        case NEON_2RM_VQABS:
                             switch (size) {
-                            case 0: gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); break;
-                            case 1: gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); break;
-                            case 2: gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); break;
-                            default: return 1;
+                            case 0: gen_helper_neon_qabs_s8(tmp, tmp); break;
+                            case 1: gen_helper_neon_qabs_s16(tmp, tmp); break;
+                            case 2: gen_helper_neon_qabs_s32(tmp, tmp); break;
+                            default: abort();
                             }
                             break;
-                        case 15: /* VQNEG */
+                        case NEON_2RM_VQNEG:
                             switch (size) {
-                            case 0: gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); break;
-                            case 1: gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); break;
-                            case 2: gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); break;
-                            default: return 1;
+                            case 0: gen_helper_neon_qneg_s8(tmp, tmp); break;
+                            case 1: gen_helper_neon_qneg_s16(tmp, tmp); break;
+                            case 2: gen_helper_neon_qneg_s32(tmp, tmp); break;
+                            default: abort();
                             }
                             break;
-                        case 16: case 19: /* VCGT #0, VCLE #0 */
+                        case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:
                             tmp2 = tcg_const_i32(0);
                             switch(size) {
                             case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;
                             case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;
                             case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;
-                            default: return 1;
+                            default: abort();
                             }
                             tcg_temp_free(tmp2);
-                            if (op == 19)
+                            if (op == NEON_2RM_VCLE0) {
                                 tcg_gen_not_i32(tmp, tmp);
+                            }
                             break;
-                        case 17: case 20: /* VCGE #0, VCLT #0 */
+                        case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:
                             tmp2 = tcg_const_i32(0);
                             switch(size) {
                             case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;
                             case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;
                             case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;
-                            default: return 1;
+                            default: abort();
                             }
                             tcg_temp_free(tmp2);
-                            if (op == 20)
+                            if (op == NEON_2RM_VCLT0) {
                                 tcg_gen_not_i32(tmp, tmp);
+                            }
                             break;
-                        case 18: /* VCEQ #0 */
+                        case NEON_2RM_VCEQ0:
                             tmp2 = tcg_const_i32(0);
                             switch(size) {
                             case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
                             case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
                             case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
-                            default: return 1;
+                            default: abort();
                             }
                             tcg_temp_free(tmp2);
                             break;
-                        case 22: /* VABS */
+                        case NEON_2RM_VABS:
                             switch(size) {
                             case 0: gen_helper_neon_abs_s8(tmp, tmp); break;
                             case 1: gen_helper_neon_abs_s16(tmp, tmp); break;
                             case 2: tcg_gen_abs_i32(tmp, tmp); break;
-                            default: return 1;
+                            default: abort();
                             }
                             break;
-                        case 23: /* VNEG */
-                            if (size == 3)
-                                return 1;
+                        case NEON_2RM_VNEG:
                             tmp2 = tcg_const_i32(0);
                             gen_neon_rsb(size, tmp, tmp2);
                             tcg_temp_free(tmp2);
                             break;
-                        case 24: case 27: /* Float VCGT #0, Float VCLE #0 */
+                        case NEON_2RM_VCGT0_F:
                             tmp2 = tcg_const_i32(0);
                             gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
                             tcg_temp_free(tmp2);
-                            if (op == 27)
-                                tcg_gen_not_i32(tmp, tmp);
                             break;
-                        case 25: case 28: /* Float VCGE #0, Float VCLT #0 */
+                        case NEON_2RM_VCGE0_F:
                             tmp2 = tcg_const_i32(0);
                             gen_helper_neon_cge_f32(tmp, tmp, tmp2);
                             tcg_temp_free(tmp2);
-                            if (op == 28)
-                                tcg_gen_not_i32(tmp, tmp);
                             break;
-                        case 26: /* Float VCEQ #0 */
+                        case NEON_2RM_VCEQ0_F:
                             tmp2 = tcg_const_i32(0);
                             gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
                             tcg_temp_free(tmp2);
                             break;
-                        case 30: /* Float VABS */
+                        case NEON_2RM_VCLE0_F:
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_cge_f32(tmp, tmp2, tmp);
+                            tcg_temp_free(tmp2);
+                            break;
+                        case NEON_2RM_VCLT0_F:
+                            tmp2 = tcg_const_i32(0);
+                            gen_helper_neon_cgt_f32(tmp, tmp2, tmp);
+                            tcg_temp_free(tmp2);
+                            break;
+                        case NEON_2RM_VABS_F:
                             gen_vfp_abs(0);
                             break;
-                        case 31: /* Float VNEG */
+                        case NEON_2RM_VNEG_F:
                             gen_vfp_neg(0);
                             break;
-                        case 32: /* VSWP */
+                        case NEON_2RM_VSWP:
                             tmp2 = neon_load_reg(rd, pass);
                             neon_store_reg(rm, pass, tmp2);
                             break;
-                        case 33: /* VTRN */
+                        case NEON_2RM_VTRN:
                             tmp2 = neon_load_reg(rd, pass);
                             switch (size) {
                             case 0: gen_neon_trn_u8(tmp, tmp2); break;
                             case 1: gen_neon_trn_u16(tmp, tmp2); break;
-                            case 2: abort();
-                            default: return 1;
+                            default: abort();
                             }
                             neon_store_reg(rm, pass, tmp2);
                             break;
-                        case 56: /* Integer VRECPE */
+                        case NEON_2RM_VRECPE:
                             gen_helper_recpe_u32(tmp, tmp, cpu_env);
                             break;
-                        case 57: /* Integer VRSQRTE */
+                        case NEON_2RM_VRSQRTE:
                             gen_helper_rsqrte_u32(tmp, tmp, cpu_env);
                             break;
-                        case 58: /* Float VRECPE */
+                        case NEON_2RM_VRECPE_F:
                             gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
                             break;
-                        case 59: /* Float VRSQRTE */
+                        case NEON_2RM_VRSQRTE_F:
                             gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
                             break;
-                        case 60: /* VCVT.F32.S32 */
+                        case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
                             gen_vfp_sito(0);
                             break;
-                        case 61: /* VCVT.F32.U32 */
+                        case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
                             gen_vfp_uito(0);
                             break;
-                        case 62: /* VCVT.S32.F32 */
+                        case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
                             gen_vfp_tosiz(0);
                             break;
-                        case 63: /* VCVT.U32.F32 */
+                        case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
                             gen_vfp_touiz(0);
                             break;
                         default:
-                            /* Reserved: 21, 29, 39-56 */
-                            return 1;
+                            /* Reserved op values were caught by the
+                             * neon_2rm_sizes[] check earlier.
+                             */
+                            abort();
                         }
-                        if (op == 30 || op == 31 || op >= 58) {
+                        if (neon_2rm_is_float_op(op)) {
                             tcg_gen_st_f32(cpu_F0s, cpu_env,
                                            neon_reg_offset(rd, pass));
                         } else {
@@ -5717,7 +6072,14 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 }
             } else if ((insn & (1 << 10)) == 0) {
                 /* VTBL, VTBX.  */
-                n = ((insn >> 5) & 0x18) + 8;
+                int n = ((insn >> 8) & 3) + 1;
+                if ((rn + n) > 32) {
+                    /* This is UNPREDICTABLE; we choose to UNDEF to avoid the
+                     * helper function running off the end of the register file.
+                     */
+                    return 1;
+                }
+                n <<= 3;
                 if (insn & (1 << 6)) {
                     tmp = neon_load_reg(rd, 0);
                 } else {
@@ -5744,6 +6106,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 tcg_temp_free_i32(tmp);
             } else if ((insn & 0x380) == 0) {
                 /* VDUP */
+                if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
+                    return 1;
+                }
                 if (insn & (1 << 19)) {
                     tmp = neon_load_reg(rm, 1);
                 } else {
@@ -6101,6 +6466,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         goto illegal_op;
     cond = insn >> 28;
     if (cond == 0xf){
+        /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
+         * choose to UNDEF. In ARMv5 and above the space is used
+         * for miscellaneous unconditional instructions.
+         */
+        ARCH(5);
+
         /* Unconditional instructions.  */
         if (((insn >> 25) & 7) == 1) {
             /* NEON Data processing.  */
@@ -6129,6 +6500,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 }
             }
             /* Otherwise PLD; v5TE+ */
+            ARCH(5TE);
             return;
         }
         if (((insn & 0x0f70f000) == 0x0450f000) ||
@@ -6265,6 +6637,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             val += (offset << 2) | ((insn >> 23) & 2) | 1;
             /* pipeline offset */
             val += 4;
+            /* protected by ARCH(5); above, near the start of uncond block */
             gen_bx_im(s, val);
             return;
         } else if ((insn & 0x0e000f00) == 0x0c000100) {
@@ -6276,6 +6649,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             }
         } else if ((insn & 0x0fe00000) == 0x0c400000) {
             /* Coprocessor double register transfer.  */
+            ARCH(5TE);
         } else if ((insn & 0x0f000010) == 0x0e000010) {
             /* Additional coprocessor register transfer.  */
         } else if ((insn & 0x0ff10020) == 0x01000000) {
@@ -6376,10 +6750,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         case 0x1:
             if (op1 == 1) {
                 /* branch/exchange thumb (bx).  */
+                ARCH(4T);
                 tmp = load_reg(s, rm);
                 gen_bx(s, tmp);
             } else if (op1 == 3) {
                 /* clz */
+                ARCH(5);
                 rd = (insn >> 12) & 0xf;
                 tmp = load_reg(s, rm);
                 gen_helper_clz(tmp, tmp);
@@ -6402,6 +6778,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             if (op1 != 1)
               goto illegal_op;
 
+            ARCH(5);
             /* branch link/exchange thumb (blx) */
             tmp = load_reg(s, rm);
             tmp2 = tcg_temp_new_i32();
@@ -6410,6 +6787,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             gen_bx(s, tmp);
             break;
         case 0x5: /* saturating add/subtract */
+            ARCH(5TE);
             rd = (insn >> 12) & 0xf;
             rn = (insn >> 16) & 0xf;
             tmp = load_reg(s, rm);
@@ -6431,12 +6809,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 goto illegal_op;
             }
             /* bkpt */
+            ARCH(5);
             gen_exception_insn(s, 4, EXCP_BKPT);
             break;
         case 0x8: /* signed multiply */
         case 0xa:
         case 0xc:
         case 0xe:
+            ARCH(5TE);
             rs = (insn >> 8) & 0xf;
             rn = (insn >> 12) & 0xf;
             rd = (insn >> 16) & 0xf;
@@ -6832,6 +7212,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     }
                     load = 1;
                 } else if (sh & 2) {
+                    ARCH(5TE);
                     /* doubleword */
                     if (sh & 1) {
                         /* store */
@@ -7172,10 +7553,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             }
             if (insn & (1 << 20)) {
                 /* Complete the load.  */
-                if (rd == 15)
-                    gen_bx(s, tmp);
-                else
-                    store_reg(s, rd, tmp);
+                store_reg_from_load(env, s, rd, tmp);
             }
             break;
         case 0x08:
@@ -7228,9 +7606,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         if (insn & (1 << 20)) {
                             /* load */
                             tmp = gen_ld32(addr, IS_USER(s));
-                            if (i == 15) {
-                                gen_bx(s, tmp);
-                            } else if (user) {
+                            if (user) {
                                 tmp2 = tcg_const_i32(i);
                                 gen_helper_set_user_reg(tmp2, tmp);
                                 tcg_temp_free_i32(tmp2);
@@ -7239,7 +7615,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                                 loaded_var = tmp;
                                 loaded_base = 1;
                             } else {
-                                store_reg(s, i, tmp);
+                                store_reg_from_load(env, s, i, tmp);
                             }
                         } else {
                             /* store */
@@ -7439,6 +7815,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
            16-bit instructions to get correct prefetch abort behavior.  */
         insn = insn_hw1;
         if ((insn & (1 << 12)) == 0) {
+            ARCH(5);
             /* Second half of blx.  */
             offset = ((insn & 0x7ff) << 1);
             tmp = load_reg(s, 14);
@@ -7639,7 +8016,8 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     }
                 }
             } else {
-                int i;
+                int i, loaded_base = 0;
+                TCGv loaded_var;
                 /* Load/store multiple.  */
                 addr = load_reg(s, rn);
                 offset = 0;
@@ -7651,6 +8029,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     tcg_gen_addi_i32(addr, addr, -offset);
                 }
 
+                TCGV_UNUSED(loaded_var);
                 for (i = 0; i < 16; i++) {
                     if ((insn & (1 << i)) == 0)
                         continue;
@@ -7659,6 +8038,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                         tmp = gen_ld32(addr, IS_USER(s));
                         if (i == 15) {
                             gen_bx(s, tmp);
+                        } else if (i == rn) {
+                            loaded_var = tmp;
+                            loaded_base = 1;
                         } else {
                             store_reg(s, i, tmp);
                         }
@@ -7669,6 +8051,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     }
                     tcg_gen_addi_i32(addr, addr, 4);
                 }
+                if (loaded_base) {
+                    store_reg(s, rn, loaded_var);
+                }
                 if (insn & (1 << 21)) {
                     /* Base register writeback.  */
                     if (insn & (1 << 24)) {
@@ -8035,6 +8420,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 } else {
                     /* blx */
                     offset &= ~(uint32_t)2;
+                    /* thumb2 bx, no need to check */
                     gen_bx_im(s, offset);
                 }
             } else if (((insn >> 23) & 7) == 7) {
@@ -8616,11 +9002,13 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             case 3:/* branch [and link] exchange thumb register */
                 tmp = load_reg(s, rm);
                 if (insn & (1 << 7)) {
+                    ARCH(5);
                     val = (uint32_t)s->pc | 1;
                     tmp2 = tcg_temp_new_i32();
                     tcg_gen_movi_i32(tmp2, val);
                     store_reg(s, 14, tmp2);
                 }
+                /* already thumb, no need to check */
                 gen_bx(s, tmp);
                 break;
             }
@@ -8980,8 +9368,9 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             /* write back the new stack pointer */
             store_reg(s, 13, addr);
             /* set the new PC value */
-            if ((insn & 0x0900) == 0x0900)
-                gen_bx(s, tmp);
+            if ((insn & 0x0900) == 0x0900) {
+                store_reg_from_load(env, s, 15, tmp);
+            }
             break;
 
         case 1: case 3: case 9: case 11: /* czb */
@@ -9012,6 +9401,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             break;
 
         case 0xe: /* bkpt */
+            ARCH(5);
             gen_exception_insn(s, 2, EXCP_BKPT);
             break;
 
@@ -9064,7 +9454,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
         break;
 
     case 12:
+    {
         /* load/store multiple */
+        TCGv loaded_var;
+        TCGV_UNUSED(loaded_var);
         rn = (insn >> 8) & 0x7;
         addr = load_reg(s, rn);
         for (i = 0; i < 8; i++) {
@@ -9072,7 +9465,11 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
                 if (insn & (1 << 11)) {
                     /* load */
                     tmp = gen_ld32(addr, IS_USER(s));
-                    store_reg(s, i, tmp);
+                    if (i == rn) {
+                        loaded_var = tmp;
+                    } else {
+                        store_reg(s, i, tmp);
+                    }
                 } else {
                     /* store */
                     tmp = load_reg(s, i);
@@ -9082,14 +9479,18 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
                 tcg_gen_addi_i32(addr, addr, 4);
             }
         }
-        /* Base register writeback.  */
         if ((insn & (1 << rn)) == 0) {
+            /* base reg not in list: base register writeback */
             store_reg(s, rn, addr);
         } else {
+            /* base reg in list: if load, complete it now */
+            if (insn & (1 << 11)) {
+                store_reg(s, rn, loaded_var);
+            }
             tcg_temp_free_i32(addr);
         }
         break;
-
+    }
     case 13:
         /* conditional branch or swi */
         cond = (insn >> 8) & 0xf;
@@ -9218,8 +9619,8 @@ static inline void gen_intermediate_code_internal(CPUState *env,
      * This is handled in the same way as restoration of the
      * PC in these situations: we will be called again with search_pc=1
      * and generate a mapping of the condexec bits for each PC in
-     * gen_opc_condexec_bits[]. gen_pc_load[] then uses this to restore
-     * the condexec bits.
+     * gen_opc_condexec_bits[]. restore_state_to_opc() then uses
+     * this to restore the condexec bits.
      *
      * Note that there are no instructions which can read the condexec
      * bits, and none which can write non-static values to them, so
@@ -9484,8 +9885,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
 #endif
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->regs[15] = gen_opc_pc[pc_pos];
     env->condexec_bits = gen_opc_condexec_bits[pc_pos];
index be9eb06fd06a29fd19e4e2bd3db2cc13d2dde281..34329e2a602200c598ba864a6b2134d42bb9cf05 100644 (file)
@@ -77,7 +77,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
 
                /* Evaluate flags after retranslation.  */
                 helper_top_evaluate_flags();
index b4648a01dee396d47051027a303ea63384d09a0a..e2607d64c01db88ec42db79adb1d5c1dbad00637 100644 (file)
@@ -596,7 +596,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
        if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
                tcg_gen_goto_tb(n);
                tcg_gen_movi_tl(env_pc, dest);
-               tcg_gen_exit_tb((long)tb + n);
+                tcg_gen_exit_tb((tcg_target_long)tb + n);
        } else {
                tcg_gen_movi_tl(env_pc, dest);
                tcg_gen_exit_tb(0);
@@ -3604,8 +3604,7 @@ void cpu_reset (CPUCRISState *env)
 #endif
 }
 
-void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
-                 unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
        env->pc = gen_opc_pc[pc_pos];
 }
index 814d13e767250f97f3ea71940d525f9067d9846b..e479a4dbd7b3c2792903783542136a50da8acb9e 100644 (file)
@@ -73,7 +73,7 @@ static const char *ext3_feature_name[] = {
 };
 
 static const char *kvm_feature_name[] = {
-    "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL,
+    "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,
@@ -182,20 +182,22 @@ static int altcmp(const char *s, const char *e, const char *altstr)
 }
 
 /* search featureset for flag *[s..e), if found set corresponding bit in
- * *pval and return success, otherwise return zero
+ * *pval and return true, otherwise return false
  */
-static int lookup_feature(uint32_t *pval, const char *s, const char *e,
-    const char **featureset)
+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)
+    for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) {
         if (*ppc && !altcmp(s, e, *ppc)) {
             *pval |= mask;
-            break;
+            found = true;
         }
-    return (mask ? 1 : 0);
+    }
+    return found;
 }
 
 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
index 6f9f709d8af532b6ed2482617f8d26002bde73cf..ee36a7181a1439332adafc28ab98b6e878600795 100644 (file)
@@ -110,11 +110,24 @@ static inline void svm_check_intercept(uint32_t type)
 #define float64_to_floatx float64_to_floatx80
 #define floatx_to_float32 floatx80_to_float32
 #define floatx_to_float64 floatx80_to_float64
+#define floatx_add floatx80_add
+#define floatx_div floatx80_div
+#define floatx_mul floatx80_mul
+#define floatx_sub floatx80_sub
+#define floatx_sqrt floatx80_sqrt
 #define floatx_abs floatx80_abs
 #define floatx_chs floatx80_chs
+#define floatx_scalbn floatx80_scalbn
 #define floatx_round_to_int floatx80_round_to_int
 #define floatx_compare floatx80_compare
 #define floatx_compare_quiet floatx80_compare_quiet
+#define floatx_is_any_nan floatx80_is_any_nan
+#define floatx_is_neg floatx80_is_neg
+#define floatx_is_zero floatx80_is_zero
+#define floatx_zero floatx80_zero
+#define floatx_one floatx80_one
+#define floatx_ln2 floatx80_ln2
+#define floatx_pi floatx80_pi
 #else
 #define floatx_to_int32 float64_to_int32
 #define floatx_to_int64 float64_to_int64
@@ -126,11 +139,24 @@ static inline void svm_check_intercept(uint32_t type)
 #define float64_to_floatx(x, e) (x)
 #define floatx_to_float32 float64_to_float32
 #define floatx_to_float64(x, e) (x)
+#define floatx_add float64_add
+#define floatx_div float64_div
+#define floatx_mul float64_mul
+#define floatx_sub float64_sub
+#define floatx_sqrt float64_sqrt
 #define floatx_abs float64_abs
 #define floatx_chs float64_chs
+#define floatx_scalbn float64_scalbn
 #define floatx_round_to_int float64_round_to_int
 #define floatx_compare float64_compare
 #define floatx_compare_quiet float64_compare_quiet
+#define floatx_is_any_nan float64_is_any_nan
+#define floatx_is_neg float64_is_neg
+#define floatx_is_zero float64_is_zero
+#define floatx_zero float64_zero
+#define floatx_one float64_one
+#define floatx_ln2 float64_ln2
+#define floatx_pi float64_pi
 #endif
 
 #define RC_MASK         0xc00
@@ -144,13 +170,7 @@ static inline void svm_check_intercept(uint32_t type)
 #ifdef USE_X86LDOUBLE
 
 /* only for x86 */
-typedef union {
-    long double d;
-    struct {
-        unsigned long long lower;
-        unsigned short upper;
-    } l;
-} CPU86_LDoubleU;
+typedef CPU_LDoubleU CPU86_LDoubleU;
 
 /* the following deal with x86 long double-precision numbers */
 #define MAXEXPD 0x7fff
@@ -162,24 +182,7 @@ typedef union {
 
 #else
 
-/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
-typedef union {
-    double d;
-#if !defined(HOST_WORDS_BIGENDIAN) && !defined(__arm__)
-    struct {
-        uint32_t lower;
-        int32_t upper;
-    } l;
-#else
-    struct {
-        int32_t upper;
-        uint32_t lower;
-    } l;
-#endif
-#ifndef __arm__
-    int64_t ll;
-#endif
-} CPU86_LDoubleU;
+typedef CPU_DoubleU CPU86_LDoubleU;
 
 /* the following deal with IEEE double-precision numbers */
 #define MAXEXPD 0x7ff
index d15fca591e204e9ac0ff6dc0b5c6c8e46b30a2fe..89df997436bf592f67a3f3d88847197e599f2451 100644 (file)
@@ -404,16 +404,10 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     env->mxcsr);
         for(i=0;i<8;i++) {
 #if defined(USE_X86LDOUBLE)
-            union {
-                long double d;
-                struct {
-                    uint64_t lower;
-                    uint16_t upper;
-                } l;
-            } tmp;
-            tmp.d = env->fpregs[i].d;
+            CPU_LDoubleU u;
+            u.d = env->fpregs[i].d;
             cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
-                        i, tmp.l.lower, tmp.l.upper);
+                        i, u.l.lower, u.l.upper);
 #else
             cpu_fprintf(f, "FPR%d=%016" PRIx64,
                         i, env->fpregs[i].mmx.q);
index a13599db8169553d275d687004461b49a9cdc059..faedc6c254f9fc0bea0b8c1cd32307c66c84a73f 100644 (file)
@@ -92,6 +92,35 @@ static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
     return cpuid;
 }
 
+#ifdef CONFIG_KVM_PARA
+struct kvm_para_features {
+    int cap;
+    int feature;
+} para_features[] = {
+    { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
+    { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
+    { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
+#ifdef KVM_CAP_ASYNC_PF
+    { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
+#endif
+    { -1, -1 }
+};
+
+static int get_para_features(CPUState *env)
+{
+    int i, features = 0;
+
+    for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) {
+        if (kvm_check_extension(env->kvm_state, para_features[i].cap)) {
+            features |= (1 << para_features[i].feature);
+        }
+    }
+
+    return features;
+}
+#endif
+
+
 uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
                                       uint32_t index, int reg)
 {
@@ -99,6 +128,9 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
     int i, max;
     uint32_t ret = 0;
     uint32_t cpuid_1_edx;
+#ifdef CONFIG_KVM_PARA
+    int has_kvm_features = 0;
+#endif
 
     max = 1;
     while ((cpuid = try_get_cpuid(env->kvm_state, max)) == NULL) {
@@ -108,6 +140,11 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
     for (i = 0; i < cpuid->nent; ++i) {
         if (cpuid->entries[i].function == function &&
             cpuid->entries[i].index == index) {
+#ifdef CONFIG_KVM_PARA
+            if (cpuid->entries[i].function == KVM_CPUID_FEATURES) {
+                has_kvm_features = 1;
+            }
+#endif
             switch (reg) {
             case R_EAX:
                 ret = cpuid->entries[i].eax;
@@ -140,38 +177,15 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
 
     qemu_free(cpuid);
 
-    return ret;
-}
-
 #ifdef CONFIG_KVM_PARA
-struct kvm_para_features {
-    int cap;
-    int feature;
-} para_features[] = {
-    { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
-    { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
-    { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
-#ifdef KVM_CAP_ASYNC_PF
-    { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
-#endif
-    { -1, -1 }
-};
-
-static int get_para_features(CPUState *env)
-{
-    int i, features = 0;
-
-    for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) {
-        if (kvm_check_extension(env->kvm_state, para_features[i].cap)) {
-            features |= (1 << para_features[i].feature);
-        }
+    /* fallback for older kernels */
+    if (!has_kvm_features && (function == KVM_CPUID_FEATURES)) {
+        ret = get_para_features(env);
     }
-#ifdef KVM_CAP_ASYNC_PF
-    has_msr_async_pf_en = features & (1 << KVM_FEATURE_ASYNC_PF);
 #endif
-    return features;
+
+    return ret;
 }
-#endif /* CONFIG_KVM_PARA */
 
 typedef struct HWPoisonPage {
     ram_addr_t ram_addr;
@@ -397,7 +411,13 @@ int kvm_arch_init_vcpu(CPUState *env)
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_FEATURES;
-    c->eax = env->cpuid_kvm_features & get_para_features(env);
+    c->eax = env->cpuid_kvm_features & kvm_arch_get_supported_cpuid(env,
+                                                KVM_CPUID_FEATURES, 0, R_EAX);
+
+#ifdef KVM_CAP_ASYNC_PF
+    has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
+#endif
+
 #endif
 
     cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
@@ -552,7 +572,7 @@ static int kvm_get_supported_msrs(KVMState *s)
             }
         }
 
-        free(kvm_msr_list);
+        qemu_free(kvm_msr_list);
     }
 
     return ret;
index 43fbd0c778ae3b946ecf46942a7a31d939cde955..3c539f37cfd7295263ba9b0fddb97b1a8cb12936 100644 (file)
@@ -17,6 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <math.h>
 #include "exec.h"
 #include "exec-all.h"
 #include "host-utils.h"
@@ -94,15 +95,25 @@ static const uint8_t rclb_table[32] = {
     6, 7, 8, 0, 1, 2, 3, 4,
 };
 
+#if defined(CONFIG_SOFTFLOAT)
+# define floatx_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL )
+# define floatx_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
+# define floatx_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
+#else
+# define floatx_lg2 (0.30102999566398119523L)
+# define floatx_l2e (1.44269504088896340739L)
+# define floatx_l2t (3.32192809488736234781L)
+#endif
+
 static const CPU86_LDouble f15rk[7] =
 {
-    0.00000000000000000000L,
-    1.00000000000000000000L,
-    3.14159265358979323851L,  /*pi*/
-    0.30102999566398119523L,  /*lg2*/
-    0.69314718055994530943L,  /*ln2*/
-    1.44269504088896340739L,  /*l2e*/
-    3.32192809488736234781L,  /*l2t*/
+    floatx_zero,
+    floatx_one,
+    floatx_pi,
+    floatx_lg2,
+    floatx_ln2,
+    floatx_l2e,
+    floatx_l2t,
 };
 
 /* broken thread support */
@@ -3431,6 +3442,28 @@ void helper_verw(target_ulong selector1)
 
 /* x87 FPU helpers */
 
+static inline double CPU86_LDouble_to_double(CPU86_LDouble a)
+{
+    union {
+        float64 f64;
+        double d;
+    } u;
+
+    u.f64 = floatx_to_float64(a, &env->fp_status);
+    return u.d;
+}
+
+static inline CPU86_LDouble double_to_CPU86_LDouble(double a)
+{
+    union {
+        float64 f64;
+        double d;
+    } u;
+
+    u.d = a;
+    return float64_to_floatx(u.f64, &env->fp_status);
+}
+
 static void fpu_set_exception(int mask)
 {
     env->fpus |= mask;
@@ -3440,9 +3473,10 @@ static void fpu_set_exception(int mask)
 
 static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
 {
-    if (b == 0.0)
+    if (floatx_is_zero(b)) {
         fpu_set_exception(FPUS_ZE);
-    return a / b;
+    }
+    return floatx_div(a, b, &env->fp_status);
 }
 
 static void fpu_raise_exception(void)
@@ -3711,22 +3745,22 @@ void helper_fucomi_ST0_FT0(void)
 
 void helper_fadd_ST0_FT0(void)
 {
-    ST0 += FT0;
+    ST0 = floatx_add(ST0, FT0, &env->fp_status);
 }
 
 void helper_fmul_ST0_FT0(void)
 {
-    ST0 *= FT0;
+    ST0 = floatx_mul(ST0, FT0, &env->fp_status);
 }
 
 void helper_fsub_ST0_FT0(void)
 {
-    ST0 -= FT0;
+    ST0 = floatx_sub(ST0, FT0, &env->fp_status);
 }
 
 void helper_fsubr_ST0_FT0(void)
 {
-    ST0 = FT0 - ST0;
+    ST0 = floatx_sub(FT0, ST0, &env->fp_status);
 }
 
 void helper_fdiv_ST0_FT0(void)
@@ -3743,24 +3777,22 @@ void helper_fdivr_ST0_FT0(void)
 
 void helper_fadd_STN_ST0(int st_index)
 {
-    ST(st_index) += ST0;
+    ST(st_index) = floatx_add(ST(st_index), ST0, &env->fp_status);
 }
 
 void helper_fmul_STN_ST0(int st_index)
 {
-    ST(st_index) *= ST0;
+    ST(st_index) = floatx_mul(ST(st_index), ST0, &env->fp_status);
 }
 
 void helper_fsub_STN_ST0(int st_index)
 {
-    ST(st_index) -= ST0;
+    ST(st_index) = floatx_sub(ST(st_index), ST0, &env->fp_status);
 }
 
 void helper_fsubr_STN_ST0(int st_index)
 {
-    CPU86_LDouble *p;
-    p = &ST(st_index);
-    *p = ST0 - *p;
+    ST(st_index) = floatx_sub(ST0, ST(st_index), &env->fp_status);
 }
 
 void helper_fdiv_STN_ST0(int st_index)
@@ -3922,9 +3954,10 @@ void helper_fbld_ST0(target_ulong ptr)
         v = ldub(ptr + i);
         val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
     }
-    tmp = val;
-    if (ldub(ptr + 9) & 0x80)
-        tmp = -tmp;
+    tmp = int64_to_floatx(val, &env->fp_status);
+    if (ldub(ptr + 9) & 0x80) {
+        floatx_chs(tmp);
+    }
     fpush();
     ST0 = tmp;
 }
@@ -3959,17 +3992,19 @@ void helper_fbst_ST0(target_ulong ptr)
 
 void helper_f2xm1(void)
 {
-    ST0 = pow(2.0,ST0) - 1.0;
+    double val = CPU86_LDouble_to_double(ST0);
+    val = pow(2.0, val) - 1.0;
+    ST0 = double_to_CPU86_LDouble(val);
 }
 
 void helper_fyl2x(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = CPU86_LDouble_to_double(ST0);
 
-    fptemp = ST0;
     if (fptemp>0.0){
-        fptemp = log(fptemp)/log(2.0);  /* log2(ST) */
-        ST1 *= fptemp;
+        fptemp = log(fptemp)/log(2.0);    /* log2(ST) */
+        fptemp *= CPU86_LDouble_to_double(ST1);
+        ST1 = double_to_CPU86_LDouble(fptemp);
         fpop();
     } else {
         env->fpus &= (~0x4700);
@@ -3979,15 +4014,15 @@ void helper_fyl2x(void)
 
 void helper_fptan(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = CPU86_LDouble_to_double(ST0);
 
-    fptemp = ST0;
     if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
         env->fpus |= 0x400;
     } else {
-        ST0 = tan(fptemp);
+        fptemp = tan(fptemp);
+        ST0 = double_to_CPU86_LDouble(fptemp);
         fpush();
-        ST0 = 1.0;
+        ST0 = floatx_one;
         env->fpus &= (~0x400);  /* C2 <-- 0 */
         /* the above code is for  |arg| < 2**52 only */
     }
@@ -3995,45 +4030,57 @@ void helper_fptan(void)
 
 void helper_fpatan(void)
 {
-    CPU86_LDouble fptemp, fpsrcop;
+    double fptemp, fpsrcop;
 
-    fpsrcop = ST1;
-    fptemp = ST0;
-    ST1 = atan2(fpsrcop,fptemp);
+    fpsrcop = CPU86_LDouble_to_double(ST1);
+    fptemp = CPU86_LDouble_to_double(ST0);
+    ST1 = double_to_CPU86_LDouble(atan2(fpsrcop, fptemp));
     fpop();
 }
 
 void helper_fxtract(void)
 {
     CPU86_LDoubleU temp;
-    unsigned int expdif;
 
     temp.d = ST0;
-    expdif = EXPD(temp) - EXPBIAS;
-    /*DP exponent bias*/
-    ST0 = expdif;
-    fpush();
-    BIASEXPONENT(temp);
-    ST0 = temp.d;
+
+    if (floatx_is_zero(ST0)) {
+        /* Easy way to generate -inf and raising division by 0 exception */
+        ST0 = floatx_div(floatx_chs(floatx_one), floatx_zero, &env->fp_status);
+        fpush();
+        ST0 = temp.d;
+    } else {
+        int expdif;
+
+        expdif = EXPD(temp) - EXPBIAS;
+        /*DP exponent bias*/
+        ST0 = int32_to_floatx(expdif, &env->fp_status);
+        fpush();
+        BIASEXPONENT(temp);
+        ST0 = temp.d;
+    }
 }
 
 void helper_fprem1(void)
 {
-    CPU86_LDouble dblq, fpsrcop, fptemp;
+    double st0, st1, dblq, fpsrcop, fptemp;
     CPU86_LDoubleU fpsrcop1, fptemp1;
     int expdif;
     signed long long int q;
 
-    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
-        ST0 = 0.0 / 0.0; /* NaN */
+    st0 = CPU86_LDouble_to_double(ST0);
+    st1 = CPU86_LDouble_to_double(ST1);
+
+    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
+        ST0 = double_to_CPU86_LDouble(0.0 / 0.0); /* NaN */
         env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
         return;
     }
 
-    fpsrcop = ST0;
-    fptemp = ST1;
-    fpsrcop1.d = fpsrcop;
-    fptemp1.d = fptemp;
+    fpsrcop = st0;
+    fptemp = st1;
+    fpsrcop1.d = ST0;
+    fptemp1.d = ST1;
     expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
 
     if (expdif < 0) {
@@ -4047,7 +4094,7 @@ void helper_fprem1(void)
         dblq = fpsrcop / fptemp;
         /* round dblq towards nearest integer */
         dblq = rint(dblq);
-        ST0 = fpsrcop - fptemp * dblq;
+        st0 = fpsrcop - fptemp * dblq;
 
         /* convert dblq to q by truncating towards zero */
         if (dblq < 0.0)
@@ -4063,31 +4110,35 @@ void helper_fprem1(void)
     } else {
         env->fpus |= 0x400;  /* C2 <-- 1 */
         fptemp = pow(2.0, expdif - 50);
-        fpsrcop = (ST0 / ST1) / fptemp;
+        fpsrcop = (st0 / st1) / fptemp;
         /* fpsrcop = integer obtained by chopping */
         fpsrcop = (fpsrcop < 0.0) ?
                   -(floor(fabs(fpsrcop))) : floor(fpsrcop);
-        ST0 -= (ST1 * fpsrcop * fptemp);
+        st0 -= (st1 * fpsrcop * fptemp);
     }
+    ST0 = double_to_CPU86_LDouble(st0);
 }
 
 void helper_fprem(void)
 {
-    CPU86_LDouble dblq, fpsrcop, fptemp;
+    double st0, st1, dblq, fpsrcop, fptemp;
     CPU86_LDoubleU fpsrcop1, fptemp1;
     int expdif;
     signed long long int q;
 
-    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
-       ST0 = 0.0 / 0.0; /* NaN */
+    st0 = CPU86_LDouble_to_double(ST0);
+    st1 = CPU86_LDouble_to_double(ST1);
+
+    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
+       ST0 = double_to_CPU86_LDouble(0.0 / 0.0); /* NaN */
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
        return;
     }
 
-    fpsrcop = (CPU86_LDouble)ST0;
-    fptemp = (CPU86_LDouble)ST1;
-    fpsrcop1.d = fpsrcop;
-    fptemp1.d = fptemp;
+    fpsrcop = st0;
+    fptemp = st1;
+    fpsrcop1.d = ST0;
+    fptemp1.d = ST1;
     expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
 
     if (expdif < 0) {
@@ -4101,7 +4152,7 @@ void helper_fprem(void)
         dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
         /* round dblq towards zero */
         dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
-        ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
+        st0 = fpsrcop/*ST0*/ - fptemp * dblq;
 
         /* convert dblq to q by truncating towards zero */
         if (dblq < 0.0)
@@ -4118,22 +4169,23 @@ void helper_fprem(void)
         int N = 32 + (expdif % 32); /* as per AMD docs */
         env->fpus |= 0x400;  /* C2 <-- 1 */
         fptemp = pow(2.0, (double)(expdif - N));
-        fpsrcop = (ST0 / ST1) / fptemp;
+        fpsrcop = (st0 / st1) / fptemp;
         /* fpsrcop = integer obtained by chopping */
         fpsrcop = (fpsrcop < 0.0) ?
                   -(floor(fabs(fpsrcop))) : floor(fpsrcop);
-        ST0 -= (ST1 * fpsrcop * fptemp);
+        st0 -= (st1 * fpsrcop * fptemp);
     }
+    ST0 = double_to_CPU86_LDouble(st0);
 }
 
 void helper_fyl2xp1(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = CPU86_LDouble_to_double(ST0);
 
-    fptemp = ST0;
     if ((fptemp+1.0)>0.0) {
         fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
-        ST1 *= fptemp;
+        fptemp *= CPU86_LDouble_to_double(ST1);
+        ST1 = double_to_CPU86_LDouble(fptemp);
         fpop();
     } else {
         env->fpus &= (~0x4700);
@@ -4143,27 +4195,23 @@ void helper_fyl2xp1(void)
 
 void helper_fsqrt(void)
 {
-    CPU86_LDouble fptemp;
-
-    fptemp = ST0;
-    if (fptemp<0.0) {
+    if (floatx_is_neg(ST0)) {
         env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
         env->fpus |= 0x400;
     }
-    ST0 = sqrt(fptemp);
+    ST0 = floatx_sqrt(ST0, &env->fp_status);
 }
 
 void helper_fsincos(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = CPU86_LDouble_to_double(ST0);
 
-    fptemp = ST0;
     if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
         env->fpus |= 0x400;
     } else {
-        ST0 = sin(fptemp);
+        ST0 = double_to_CPU86_LDouble(sin(fptemp));
         fpush();
-        ST0 = cos(fptemp);
+        ST0 = double_to_CPU86_LDouble(cos(fptemp));
         env->fpus &= (~0x400);  /* C2 <-- 0 */
         /* the above code is for  |arg| < 2**63 only */
     }
@@ -4176,18 +4224,22 @@ void helper_frndint(void)
 
 void helper_fscale(void)
 {
-    ST0 = ldexp (ST0, (int)(ST1));
+    if (floatx_is_any_nan(ST1)) {
+        ST0 = ST1;
+    } else {
+        int n = floatx_to_int32_round_to_zero(ST1, &env->fp_status);
+        ST0 = floatx_scalbn(ST0, n, &env->fp_status);
+    }
 }
 
 void helper_fsin(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = CPU86_LDouble_to_double(ST0);
 
-    fptemp = ST0;
     if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
         env->fpus |= 0x400;
     } else {
-        ST0 = sin(fptemp);
+        ST0 = double_to_CPU86_LDouble(sin(fptemp));
         env->fpus &= (~0x400);  /* C2 <-- 0 */
         /* the above code is for  |arg| < 2**53 only */
     }
@@ -4195,13 +4247,12 @@ void helper_fsin(void)
 
 void helper_fcos(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = CPU86_LDouble_to_double(ST0);
 
-    fptemp = ST0;
     if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
         env->fpus |= 0x400;
     } else {
-        ST0 = cos(fptemp);
+        ST0 = double_to_CPU86_LDouble(cos(fptemp));
         env->fpus &= (~0x400);  /* C2 <-- 0 */
         /* the above code is for  |arg5 < 2**63 only */
     }
@@ -4783,16 +4834,6 @@ void helper_boundl(target_ulong a0, int v)
     }
 }
 
-static float approx_rsqrt(float a)
-{
-    return 1.0 / sqrt(a);
-}
-
-static float approx_rcp(float a)
-{
-    return 1.0 / a;
-}
-
 #if !defined(CONFIG_USER_ONLY)
 
 #define MMUSUFFIX _mmu
@@ -4837,7 +4878,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         raise_exception_err(env->exception_index, env->error_code);
index 3232abd9657c2f1189a160fbdb27b7ef2d4b361d..703be99cd279c5a0953933c20e4dee234b1bb278 100644 (file)
@@ -778,28 +778,38 @@ int64_t helper_cvttsd2sq(XMMReg *s)
 
 void helper_rsqrtps(XMMReg *d, XMMReg *s)
 {
-    d->XMM_S(0) = approx_rsqrt(s->XMM_S(0));
-    d->XMM_S(1) = approx_rsqrt(s->XMM_S(1));
-    d->XMM_S(2) = approx_rsqrt(s->XMM_S(2));
-    d->XMM_S(3) = approx_rsqrt(s->XMM_S(3));
+    d->XMM_S(0) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(0), &env->sse_status),
+                              &env->sse_status);
+    d->XMM_S(1) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(1), &env->sse_status),
+                              &env->sse_status);
+    d->XMM_S(2) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(2), &env->sse_status),
+                              &env->sse_status);
+    d->XMM_S(3) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(3), &env->sse_status),
+                              &env->sse_status);
 }
 
 void helper_rsqrtss(XMMReg *d, XMMReg *s)
 {
-    d->XMM_S(0) = approx_rsqrt(s->XMM_S(0));
+    d->XMM_S(0) = float32_div(float32_one,
+                              float32_sqrt(s->XMM_S(0), &env->sse_status),
+                              &env->sse_status);
 }
 
 void helper_rcpps(XMMReg *d, XMMReg *s)
 {
-    d->XMM_S(0) = approx_rcp(s->XMM_S(0));
-    d->XMM_S(1) = approx_rcp(s->XMM_S(1));
-    d->XMM_S(2) = approx_rcp(s->XMM_S(2));
-    d->XMM_S(3) = approx_rcp(s->XMM_S(3));
+    d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status);
+    d->XMM_S(1) = float32_div(float32_one, s->XMM_S(1), &env->sse_status);
+    d->XMM_S(2) = float32_div(float32_one, s->XMM_S(2), &env->sse_status);
+    d->XMM_S(3) = float32_div(float32_one, s->XMM_S(3), &env->sse_status);
 }
 
 void helper_rcpss(XMMReg *d, XMMReg *s)
 {
-    d->XMM_S(0) = approx_rcp(s->XMM_S(0));
+    d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status);
 }
 
 static inline uint64_t helper_extrq(uint64_t src, int shift, int len)
@@ -921,14 +931,14 @@ void helper_ ## name ## sd (Reg *d, Reg *s)\
     d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
 }
 
-#define FPU_CMPEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? -1 : 0
+#define FPU_CMPEQ(size, a, b) float ## size ## _eq_quiet(a, b, &env->sse_status) ? -1 : 0
 #define FPU_CMPLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0
 #define FPU_CMPLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? -1 : 0
-#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? - 1 : 0
-#define FPU_CMPNEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? 0 : -1
+#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? - 1 : 0
+#define FPU_CMPNEQ(size, a, b) float ## size ## _eq_quiet(a, b, &env->sse_status) ? 0 : -1
 #define FPU_CMPNLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1
 #define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1
-#define FPU_CMPORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? 0 : -1
+#define FPU_CMPORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? 0 : -1
 
 SSE_HELPER_CMP(cmpeq, FPU_CMPEQ)
 SSE_HELPER_CMP(cmplt, FPU_CMPLT)
@@ -1216,8 +1226,8 @@ void helper_pfadd(MMXReg *d, MMXReg *s)
 
 void helper_pfcmpeq(MMXReg *d, MMXReg *s)
 {
-    d->MMX_L(0) = float32_eq(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0;
-    d->MMX_L(1) = float32_eq(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0;
+    d->MMX_L(0) = float32_eq_quiet(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0;
+    d->MMX_L(1) = float32_eq_quiet(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0;
 }
 
 void helper_pfcmpge(MMXReg *d, MMXReg *s)
@@ -1272,14 +1282,16 @@ void helper_pfpnacc(MMXReg *d, MMXReg *s)
 
 void helper_pfrcp(MMXReg *d, MMXReg *s)
 {
-    d->MMX_S(0) = approx_rcp(s->MMX_S(0));
+    d->MMX_S(0) = float32_div(float32_one, s->MMX_S(0), &env->mmx_status);
     d->MMX_S(1) = d->MMX_S(0);
 }
 
 void helper_pfrsqrt(MMXReg *d, MMXReg *s)
 {
     d->MMX_L(1) = s->MMX_L(0) & 0x7fffffff;
-    d->MMX_S(1) = approx_rsqrt(d->MMX_S(1));
+    d->MMX_S(1) = float32_div(float32_one,
+                              float32_sqrt(d->MMX_S(1), &env->mmx_status),
+                              &env->mmx_status);
     d->MMX_L(1) |= s->MMX_L(0) & 0x80000000;
     d->MMX_L(0) = d->MMX_L(1);
 }
index c00845038a8d1666b163c94a40cd4dce5eb9ef48..199302e517fc677dc984c8ebfe4f53aa60372164 100644 (file)
@@ -2274,7 +2274,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
         /* jump to same page: we can use a direct jump */
         tcg_gen_goto_tb(tb_num);
         gen_jmp_im(eip);
-        tcg_gen_exit_tb((long)tb + tb_num);
+        tcg_gen_exit_tb((tcg_target_long)tb + tb_num);
     } else {
         /* jump to another page: currently not optimized */
         gen_jmp_im(eip);
@@ -7890,8 +7890,7 @@ void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     int cc_op;
 #ifdef DEBUG_DISAS
@@ -7903,8 +7902,8 @@ void gen_pc_load(CPUState *env, TranslationBlock *tb,
                 qemu_log("0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]);
             }
         }
-        qemu_log("spc=0x%08lx pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n",
-                searched_pc, pc_pos, gen_opc_pc[pc_pos] - tb->cs_base,
+        qemu_log("pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n",
+                pc_pos, gen_opc_pc[pc_pos] - tb->cs_base,
                 (uint32_t)tb->cs_base);
     }
 #endif
index 318e2cf6e0867aead8810bc77a2401f60f262335..4f3e7e0fcb75a2884b61aa685980e09ea6c93594 100644 (file)
@@ -76,11 +76,7 @@ void do_interrupt(CPUState *env)
         env->regs[R_BA] = env->pc;
         env->ie |= (env->ie & IE_IE) ? IE_BIE : 0;
         env->ie &= ~IE_IE;
-        if (env->dc & DC_RE) {
-            env->pc = env->deba + (env->exception_index * 32);
-        } else {
-            env->pc = env->eba + (env->exception_index * 32);
-        }
+        env->pc = env->deba + (env->exception_index * 32);
         log_cpu_state_mask(CPU_LOG_INT, env, 0);
         break;
     default:
diff --git a/target-lm32/lm32-decode.h b/target-lm32/lm32-decode.h
deleted file mode 100644 (file)
index f745b39..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *  LatticeMico32 instruction decoding macros.
- *
- *  Copyright (c) 2010 Michael Walle <michael@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/>.
- */
-
-/* Convenient binary macros */
-#define HEX__(n) 0x##n##LU
-#define B8__(x) (((x&0x0000000FLU) ? 1 : 0) \
-                  + ((x&0x000000F0LU) ? 2 : 0) \
-                  + ((x&0x00000F00LU) ? 4 : 0) \
-                  + ((x&0x0000F000LU) ? 8 : 0) \
-                  + ((x&0x000F0000LU) ? 16 : 0) \
-                  + ((x&0x00F00000LU) ? 32 : 0) \
-                  + ((x&0x0F000000LU) ? 64 : 0) \
-                  + ((x&0xF0000000LU) ? 128 : 0))
-#define B8(d) ((unsigned char)B8__(HEX__(d)))
-
-/* Decode logic, value and mask.  */
-#define DEC_ADD     {B8(00001101), B8(00011111)}
-#define DEC_AND     {B8(00001000), B8(00011111)}
-#define DEC_ANDHI   {B8(00011000), B8(00111111)}
-#define DEC_B       {B8(00110000), B8(00111111)}
-#define DEC_BI      {B8(00111000), B8(00111111)}
-#define DEC_BE      {B8(00010001), B8(00111111)}
-#define DEC_BG      {B8(00010010), B8(00111111)}
-#define DEC_BGE     {B8(00010011), B8(00111111)}
-#define DEC_BGEU    {B8(00010100), B8(00111111)}
-#define DEC_BGU     {B8(00010101), B8(00111111)}
-#define DEC_BNE     {B8(00010111), B8(00111111)}
-#define DEC_CALL    {B8(00110110), B8(00111111)}
-#define DEC_CALLI   {B8(00111110), B8(00111111)}
-#define DEC_CMPE    {B8(00011001), B8(00011111)}
-#define DEC_CMPG    {B8(00011010), B8(00011111)}
-#define DEC_CMPGE   {B8(00011011), B8(00011111)}
-#define DEC_CMPGEU  {B8(00011100), B8(00011111)}
-#define DEC_CMPGU   {B8(00011101), B8(00011111)}
-#define DEC_CMPNE   {B8(00011111), B8(00011111)}
-#define DEC_DIVU    {B8(00100011), B8(00111111)}
-#define DEC_LB      {B8(00000100), B8(00111111)}
-#define DEC_LBU     {B8(00010000), B8(00111111)}
-#define DEC_LH      {B8(00000111), B8(00111111)}
-#define DEC_LHU     {B8(00001011), B8(00111111)}
-#define DEC_LW      {B8(00001010), B8(00111111)}
-#define DEC_MODU    {B8(00110001), B8(00111111)}
-#define DEC_MUL     {B8(00000010), B8(00011111)}
-#define DEC_NOR     {B8(00000001), B8(00011111)}
-#define DEC_OR      {B8(00001110), B8(00011111)}
-#define DEC_ORHI    {B8(00011110), B8(00111111)}
-#define DEC_RAISE   {B8(00101011), B8(00111111)}
-#define DEC_RCSR    {B8(00100100), B8(00111111)}
-#define DEC_SB      {B8(00001100), B8(00111111)}
-#define DEC_SEXTB   {B8(00101100), B8(00111111)}
-#define DEC_SEXTH   {B8(00110111), B8(00111111)}
-#define DEC_SH      {B8(00000011), B8(00111111)}
-#define DEC_SL      {B8(00001111), B8(00011111)}
-#define DEC_SR      {B8(00000101), B8(00011111)}
-#define DEC_SRU     {B8(00000000), B8(00011111)}
-#define DEC_SUB     {B8(00110010), B8(00111111)}
-#define DEC_SW      {B8(00010110), B8(00111111)}
-#define DEC_USER    {B8(00110011), B8(00111111)}
-#define DEC_WCSR    {B8(00110100), B8(00111111)}
-#define DEC_XNOR    {B8(00001001), B8(00011111)}
-#define DEC_XOR     {B8(00000110), B8(00011111)}
-
index e84ba488be33d9a2b3e540c8932430a49da78ddb..c72b1df47b1bc2fcc56337f8814dccd4acbfb266 100644 (file)
@@ -95,7 +95,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         cpu_loop_exit();
index 0b0e405fe74999e097b3b82e51b50b0e09d0ee08..bcd52fe73dc806c7093b152d82dc86fea8444f69 100644 (file)
@@ -29,7 +29,6 @@
 #include "disas.h"
 #include "helper.h"
 #include "tcg-op.h"
-#include "lm32-decode.h"
 #include "qemu-common.h"
 
 #include "hw/lm32_pic.h"
@@ -139,7 +138,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
             likely(!dc->singlestep_enabled)) {
         tcg_gen_goto_tb(n);
         tcg_gen_movi_tl(cpu_pc, dest);
-        tcg_gen_exit_tb((long)tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         tcg_gen_movi_tl(cpu_pc, dest);
         if (dc->singlestep_enabled) {
@@ -583,7 +582,7 @@ static void dec_orhi(DisasContext *dc)
     tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
 }
 
-static void dec_raise(DisasContext *dc)
+static void dec_scall(DisasContext *dc)
 {
     TCGv t0;
     int l1;
@@ -599,36 +598,10 @@ static void dec_raise(DisasContext *dc)
     t0 = tcg_temp_new();
     l1 = gen_new_label();
 
-    /* save IE.IE */
-    tcg_gen_andi_tl(t0, cpu_ie, IE_IE);
-
-    /* IE.IE = 0 */
-    tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
-
     if (dc->imm5 == 7) {
-        /* IE.EIE = IE.IE */
-        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_EIE);
-        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_IE, l1);
-        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_EIE);
-        gen_set_label(l1);
-
-        /* gpr[ea] = PC */
-        tcg_gen_movi_tl(cpu_R[R_EA], dc->pc);
-        tcg_temp_free(t0);
-
         tcg_gen_movi_tl(cpu_pc, dc->pc);
         t_gen_raise_exception(dc, EXCP_SYSTEMCALL);
     } else {
-        /* IE.BIE = IE.IE */
-        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_BIE);
-        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_IE, l1);
-        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_BIE);
-        gen_set_label(l1);
-
-        /* gpr[ba] = PC */
-        tcg_gen_movi_tl(cpu_R[R_BA], dc->pc);
-        tcg_temp_free(t0);
-
         tcg_gen_movi_tl(cpu_pc, dc->pc);
         t_gen_raise_exception(dc, EXCP_BREAKPOINT);
     }
@@ -963,66 +936,28 @@ static void dec_xor(DisasContext *dc)
     }
 }
 
-typedef struct {
-    struct {
-        uint32_t bits;
-        uint32_t mask;
-    };
-    void (*dec)(DisasContext *dc);
-} DecoderInfo;
+static void dec_ill(DisasContext *dc)
+{
+    cpu_abort(dc->env, "unknown opcode 0x%02x\n", dc->opcode);
+}
 
+typedef void (*DecoderInfo)(DisasContext *dc);
 static const DecoderInfo decinfo[] = {
-    {DEC_ADD, dec_add},
-    {DEC_AND, dec_and},
-    {DEC_ANDHI, dec_andhi},
-    {DEC_B, dec_b},
-    {DEC_BI, dec_bi},
-    {DEC_BE, dec_be},
-    {DEC_BG, dec_bg},
-    {DEC_BGE, dec_bge},
-    {DEC_BGEU, dec_bgeu},
-    {DEC_BGU, dec_bgu},
-    {DEC_BNE, dec_bne},
-    {DEC_CALL, dec_call},
-    {DEC_CALLI, dec_calli},
-    {DEC_CMPE, dec_cmpe},
-    {DEC_CMPG, dec_cmpg},
-    {DEC_CMPGE, dec_cmpge},
-    {DEC_CMPGEU, dec_cmpgeu},
-    {DEC_CMPGU, dec_cmpgu},
-    {DEC_CMPNE, dec_cmpne},
-    {DEC_DIVU, dec_divu},
-    {DEC_LB, dec_lb},
-    {DEC_LBU, dec_lbu},
-    {DEC_LH, dec_lh},
-    {DEC_LHU, dec_lhu},
-    {DEC_LW, dec_lw},
-    {DEC_MODU, dec_modu},
-    {DEC_MUL, dec_mul},
-    {DEC_NOR, dec_nor},
-    {DEC_OR, dec_or},
-    {DEC_ORHI, dec_orhi},
-    {DEC_RAISE, dec_raise},
-    {DEC_RCSR, dec_rcsr},
-    {DEC_SB, dec_sb},
-    {DEC_SEXTB, dec_sextb},
-    {DEC_SEXTH, dec_sexth},
-    {DEC_SH, dec_sh},
-    {DEC_SL, dec_sl},
-    {DEC_SR, dec_sr},
-    {DEC_SRU, dec_sru},
-    {DEC_SUB, dec_sub},
-    {DEC_SW, dec_sw},
-    {DEC_USER, dec_user},
-    {DEC_WCSR, dec_wcsr},
-    {DEC_XNOR, dec_xnor},
-    {DEC_XOR, dec_xor},
+    dec_sru, dec_nor, dec_mul, dec_sh, dec_lb, dec_sr, dec_xor, dec_lh,
+    dec_and, dec_xnor, dec_lw, dec_lhu, dec_sb, dec_add, dec_or, dec_sl,
+    dec_lbu, dec_be, dec_bg, dec_bge, dec_bgeu, dec_bgu, dec_sw, dec_bne,
+    dec_andhi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_orhi,
+    dec_cmpne,
+    dec_sru, dec_nor, dec_mul, dec_divu, dec_rcsr, dec_sr, dec_xor, dec_ill,
+    dec_and, dec_xnor, dec_ill, dec_scall, dec_sextb, dec_add, dec_or, dec_sl,
+    dec_b, dec_modu, dec_sub, dec_user, dec_wcsr, dec_ill, dec_call, dec_sexth,
+    dec_bi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_calli,
+    dec_cmpne
 };
 
 static inline void decode(DisasContext *dc)
 {
     uint32_t ir;
-    int i;
 
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
         tcg_gen_debug_insn_start(dc->pc);
@@ -1061,15 +996,10 @@ static inline void decode(DisasContext *dc)
         dc->format = OP_FMT_RI;
     }
 
-    /* Large switch for all insns.  */
-    for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
-        if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
-            decinfo[i].dec(dc);
-            return;
-        }
-    }
+    assert(ARRAY_SIZE(decinfo) == 64);
+    assert(dc->opcode < 64);
 
-    cpu_abort(dc->env, "unknown opcode 0x%02x\n", dc->opcode);
+    decinfo[dc->opcode](dc);
 }
 
 static void check_breakpoint(CPUState *env, DisasContext *dc)
@@ -1256,8 +1186,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
     cpu_fprintf(f, "\n\n");
 }
 
-void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
-                 unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->pc = gen_opc_pc[pc_pos];
 }
index 07111073f81af975e90ed6f190feba3ecbf4e53c..9b13bdbcc24680fe2f7770b0eb5f6df4045353a8 100644 (file)
@@ -68,7 +68,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         cpu_loop_exit();
index 6f72a2bdd2fc4ccd5270aa6bfb0c6118a590025b..9e5578d4556f41ab45c5732a1050704ecf602ccc 100644 (file)
@@ -861,7 +861,7 @@ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
                (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
         tcg_gen_goto_tb(n);
         tcg_gen_movi_i32(QREG_PC, dest);
-        tcg_gen_exit_tb((long)tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         gen_jmp_im(s, dest);
         tcg_gen_exit_tb(0);
@@ -3113,8 +3113,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
     cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result);
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->pc = gen_opc_pc[pc_pos];
 }
index 14d4d427305521fdc5064eb4f41253a786af7979..536222e4b89a1ad252ca06098a387fc7f3c7e7b9 100644 (file)
@@ -79,6 +79,8 @@ struct CPUMBState;
 #define          ESR_DIZ       (1<<11) /* Zone Protection */
 #define          ESR_S         (1<<10) /* Store instruction */
 
+#define          ESR_ESS_FSL_OFFSET     5
+
 #define          ESR_EC_FSL             0
 #define          ESR_EC_UNALIGNED_DATA  1
 #define          ESR_EC_ILLEGAL_OP      2
@@ -91,6 +93,7 @@ struct CPUMBState;
 #define          ESR_EC_INSN_STORAGE    9
 #define          ESR_EC_DATA_TLB        10
 #define          ESR_EC_INSN_TLB        11
+#define          ESR_EC_MASK            31
 
 /* Floating Point Status Register (FSR) Bits */
 #define FSR_IO          (1<<4) /* Invalid operation */
@@ -194,7 +197,7 @@ struct CPUMBState;
 #define PVR11_MMU_ITLB_SIZE             0x38000000
 #define PVR11_MMU_DTLB_SIZE             0x07000000
 #define PVR11_MMU_TLB_ACCESS            0x00C00000
-#define PVR11_MMU_ZONES                 0x003C0000
+#define PVR11_MMU_ZONES                 0x003E0000
 /* MSR Reset value PVR mask */
 #define PVR11_MSR_RESET_VALUE_MASK      0x000007FF
 
@@ -211,6 +214,13 @@ struct CPUMBState;
 #define CC_EQ  0
 
 #define NB_MMU_MODES    3
+
+#define STREAM_EXCEPTION (1 << 0)
+#define STREAM_ATOMIC    (1 << 1)
+#define STREAM_TEST      (1 << 2)
+#define STREAM_CONTROL   (1 << 3)
+#define STREAM_NONBLOCK  (1 << 4)
+
 typedef struct CPUMBState {
     uint32_t debug;
     uint32_t btaken;
index 1696b885b68957939727554dd41f5374ea69f7a8..b92aa34d05b800cfe0bbc3606502d50b12c094ff 100644 (file)
@@ -33,4 +33,7 @@ DEF_HELPER_2(mmu_write, void, i32, i32)
 
 DEF_HELPER_4(memalign, void, i32, i32, i32, i32)
 
+DEF_HELPER_2(get, i32, i32, i32)
+DEF_HELPER_3(put, void, i32, i32, i32)
+
 #include "def-helper.h"
index 4a274768d3602b98346323d4d7d64f3fc8d6c680..401319ed46f1696878aba0ffeda2bd2850b10a3c 100644 (file)
@@ -50,3 +50,6 @@
 #define DEC_BR      {B8(00100110), B8(00110111)}
 #define DEC_BCC     {B8(00100111), B8(00110111)}
 #define DEC_RTS     {B8(00101101), B8(00111111)}
+
+#define DEC_STREAM  {B8(00010011), B8(00110111)}
+
index d75a53cc547396d7eaf88b4c536dcfcec9a5bbf6..c7b2f97d96f1054a159e204a5747fc8c5f5529b5 100644 (file)
@@ -60,7 +60,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         cpu_loop_exit();
@@ -69,6 +69,41 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
 }
 #endif
 
+void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
+{
+    int test = ctrl & STREAM_TEST;
+    int atomic = ctrl & STREAM_ATOMIC;
+    int control = ctrl & STREAM_CONTROL;
+    int nonblock = ctrl & STREAM_NONBLOCK;
+    int exception = ctrl & STREAM_EXCEPTION;
+
+    qemu_log("Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
+             id, data,
+             test ? "t" : "",
+             nonblock ? "n" : "",
+             exception ? "e" : "",
+             control ? "c" : "",
+             atomic ? "a" : "");
+}
+
+uint32_t helper_get(uint32_t id, uint32_t ctrl)
+{
+    int test = ctrl & STREAM_TEST;
+    int atomic = ctrl & STREAM_ATOMIC;
+    int control = ctrl & STREAM_CONTROL;
+    int nonblock = ctrl & STREAM_NONBLOCK;
+    int exception = ctrl & STREAM_EXCEPTION;
+
+    qemu_log("Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
+             id,
+             test ? "t" : "",
+             nonblock ? "n" : "",
+             exception ? "e" : "",
+             control ? "c" : "",
+             atomic ? "a" : "");
+    return 0xdead0000 | id;
+}
+
 void helper_raise_exception(uint32_t index)
 {
     env->exception_index = index;
@@ -303,7 +338,7 @@ uint32_t helper_fcmp_eq(uint32_t a, uint32_t b)
     set_float_exception_flags(0, &env->fp_status);
     fa.l = a;
     fb.l = b;
-    r = float32_eq(fa.f, fb.f, &env->fp_status);
+    r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
     flags = get_float_exception_flags(&env->fp_status);
     update_fpu_flags(flags & float_flag_invalid);
 
@@ -349,7 +384,7 @@ uint32_t helper_fcmp_ne(uint32_t a, uint32_t b)
     fa.l = a;
     fb.l = b;
     set_float_exception_flags(0, &env->fp_status);
-    r = !float32_eq(fa.f, fb.f, &env->fp_status);
+    r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
     flags = get_float_exception_flags(&env->fp_status);
     update_fpu_flags(flags & float_flag_invalid);
 
index fdb2b40df9fafe420f03d44e0ce1e0fe6bf4f141..b47b92e9099da364a347a268cd32d7ab165a887d 100644 (file)
@@ -146,7 +146,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
     if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
         tcg_gen_goto_tb(n);
         tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
-        tcg_gen_exit_tb((long)tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
         tcg_gen_exit_tb(0);
@@ -923,7 +923,7 @@ static void dec_load(DisasContext *dc)
     /*
      * When doing reverse accesses we need to do two things.
      *
-     * 1. Reverse the address wrt endianess.
+     * 1. Reverse the address wrt endianness.
      * 2. Byteswap the data lanes on the way back into the CPU core.
      */
     if (rev && size != 4) {
@@ -1476,6 +1476,42 @@ static void dec_null(DisasContext *dc)
     dc->abort_at_next_insn = 1;
 }
 
+/* Insns connected to FSL or AXI stream attached devices.  */
+static void dec_stream(DisasContext *dc)
+{
+    int mem_index = cpu_mmu_index(dc->env);
+    TCGv_i32 t_id, t_ctrl;
+    int ctrl;
+
+    LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
+            dc->type_b ? "" : "d", dc->imm);
+
+    if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) {
+        tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+        t_gen_raise_exception(dc, EXCP_HW_EXCP);
+        return;
+    }
+
+    t_id = tcg_temp_new();
+    if (dc->type_b) {
+        tcg_gen_movi_tl(t_id, dc->imm & 0xf);
+        ctrl = dc->imm >> 10;
+    } else {
+        tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf);
+        ctrl = dc->imm >> 5;
+    }
+
+    t_ctrl = tcg_const_tl(ctrl);
+
+    if (dc->rd == 0) {
+        gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
+    } else {
+        gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
+    }
+    tcg_temp_free(t_id);
+    tcg_temp_free(t_ctrl);
+}
+
 static struct decoder_info {
     struct {
         uint32_t bits;
@@ -1500,6 +1536,7 @@ static struct decoder_info {
     {DEC_MUL, dec_mul},
     {DEC_DIV, dec_div},
     {DEC_MSR, dec_msr},
+    {DEC_STREAM, dec_stream},
     {{0, 0}, dec_null}
 };
 
@@ -1903,8 +1940,7 @@ void cpu_reset (CPUState *env)
 #endif
 }
 
-void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
-                 unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->sregs[SR_PC] = gen_opc_pc[pc_pos];
 }
index 2419aa93d2e8b69240a610a8a7808831d42b4e19..0b98d10266ba3d66636ac153860395dc1c625e87 100644 (file)
@@ -63,7 +63,7 @@ union fpr_t {
     uint32_t w[2]; /* binary single fixed-point */
 };
 /* define FP_ENDIAN_IDX to access the same location
- * in the fpr_t union regardless of the host endianess
+ * in the fpr_t union regardless of the host endianness
  */
 #if defined(HOST_WORDS_BIGENDIAN)
 #  define FP_ENDIAN_IDX 1
index bd16ce35430cdbe884369fc7ca9b8507ec6f545a..b8e4991f32b3a768ba820c2754e5cafc514b5cf6 100644 (file)
@@ -54,7 +54,7 @@ static void do_restore_state (void *pc_ptr)
     
     tb = tb_find_pc (pc);
     if (tb) {
-        cpu_restore_state (tb, env, pc, NULL);
+        cpu_restore_state(tb, env, pc);
     }
 }
 #endif
@@ -1972,7 +1972,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         helper_raise_exception_err(env->exception_index, env->error_code);
@@ -2077,22 +2077,27 @@ void helper_ctc1 (target_ulong arg1, uint32_t reg)
         helper_raise_exception(EXCP_FPE);
 }
 
-static inline char ieee_ex_to_mips(char xcpt)
+static inline int ieee_ex_to_mips(int xcpt)
 {
-    return (xcpt & float_flag_inexact) >> 5 |
-           (xcpt & float_flag_underflow) >> 3 |
-           (xcpt & float_flag_overflow) >> 1 |
-           (xcpt & float_flag_divbyzero) << 1 |
-           (xcpt & float_flag_invalid) << 4;
-}
-
-static inline char mips_ex_to_ieee(char xcpt)
-{
-    return (xcpt & FP_INEXACT) << 5 |
-           (xcpt & FP_UNDERFLOW) << 3 |
-           (xcpt & FP_OVERFLOW) << 1 |
-           (xcpt & FP_DIV0) >> 1 |
-           (xcpt & FP_INVALID) >> 4;
+    int ret = 0;
+    if (xcpt) {
+        if (xcpt & float_flag_invalid) {
+            ret |= FP_INVALID;
+        }
+        if (xcpt & float_flag_overflow) {
+            ret |= FP_OVERFLOW;
+        }
+        if (xcpt & float_flag_underflow) {
+            ret |= FP_UNDERFLOW;
+        }
+        if (xcpt & float_flag_divbyzero) {
+            ret |= FP_DIV0;
+        }
+        if (xcpt & float_flag_inexact) {
+            ret |= FP_INEXACT;
+        }
+    }
+    return ret;
 }
 
 static inline void update_fcr31(void)
@@ -2869,7 +2874,9 @@ uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
 #define FOP_COND_D(op, cond)                                   \
 void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
 {                                                              \
-    int c = cond;                                              \
+    int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
+    c = cond;                                                  \
     update_fcr31();                                            \
     if (c)                                                     \
         SET_FP_COND(cc, env->active_fpu);                      \
@@ -2879,6 +2886,7 @@ void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
 void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
 {                                                              \
     int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
     fdt0 = float64_abs(fdt0);                                  \
     fdt1 = float64_abs(fdt1);                                  \
     c = cond;                                                  \
@@ -2889,45 +2897,33 @@ void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
         CLEAR_FP_COND(cc, env->active_fpu);                    \
 }
 
-static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
-{
-    if (float64_is_signaling_nan(a) ||
-        float64_is_signaling_nan(b) ||
-        (sig && (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)))) {
-        float_raise(float_flag_invalid, status);
-        return 1;
-    } else if (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_D(f,   (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0))
-FOP_COND_D(un,  float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status))
-FOP_COND_D(eq,  !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
+ * but float64_unordered_quiet() is still called. */
+FOP_COND_D(f,   (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_COND_D(un,  float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
+FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_D(sf,  (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0))
-FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status))
-FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(lt,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(le,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
+ * but float64_unordered() is still called. */
+FOP_COND_D(sf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
+FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(lt,  float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
 
 #define FOP_COND_S(op, cond)                                   \
 void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
 {                                                              \
-    int c = cond;                                              \
+    int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
+    c = cond;                                                  \
     update_fcr31();                                            \
     if (c)                                                     \
         SET_FP_COND(cc, env->active_fpu);                      \
@@ -2937,6 +2933,7 @@ void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
 void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
 {                                                              \
     int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
     fst0 = float32_abs(fst0);                                  \
     fst1 = float32_abs(fst1);                                  \
     c = cond;                                                  \
@@ -2947,51 +2944,39 @@ void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
         CLEAR_FP_COND(cc, env->active_fpu);                    \
 }
 
-static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
-{
-    if (float32_is_signaling_nan(a) ||
-        float32_is_signaling_nan(b) ||
-        (sig && (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)))) {
-        float_raise(float_flag_invalid, status);
-        return 1;
-    } else if (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_S(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0))
-FOP_COND_S(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status))
-FOP_COND_S(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
+ * but float32_unordered_quiet() is still called. */
+FOP_COND_S(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_COND_S(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
+FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_S(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0))
-FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status))
-FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
+ * but float32_unordered() is still called. */
+FOP_COND_S(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
+FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
 
 #define FOP_COND_PS(op, condl, condh)                           \
 void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
 {                                                               \
-    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
-    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
-    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
-    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
-    int cl = condl;                                             \
-    int ch = condh;                                             \
-                                                                \
+    uint32_t fst0, fsth0, fst1, fsth1;                          \
+    int ch, cl;                                                 \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);   \
+    fst0 = fdt0 & 0XFFFFFFFF;                                   \
+    fsth0 = fdt0 >> 32;                                         \
+    fst1 = fdt1 & 0XFFFFFFFF;                                   \
+    fsth1 = fdt1 >> 32;                                         \
+    cl = condl;                                                 \
+    ch = condh;                                                 \
     update_fcr31();                                             \
     if (cl)                                                     \
         SET_FP_COND(cc, env->active_fpu);                       \
@@ -3004,13 +2989,14 @@ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
 }                                                               \
 void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
 {                                                               \
-    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
-    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
-    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
-    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
-    int cl = condl;                                             \
-    int ch = condh;                                             \
-                                                                \
+    uint32_t fst0, fsth0, fst1, fsth1;                          \
+    int ch, cl;                                                 \
+    fst0 = float32_abs(fdt0 & 0XFFFFFFFF);                      \
+    fsth0 = float32_abs(fdt0 >> 32);                            \
+    fst1 = float32_abs(fdt1 & 0XFFFFFFFF);                      \
+    fsth1 = float32_abs(fdt1 >> 32);                            \
+    cl = condl;                                                 \
+    ch = condh;                                                 \
     update_fcr31();                                             \
     if (cl)                                                     \
         SET_FP_COND(cc, env->active_fpu);                       \
@@ -3023,38 +3009,38 @@ void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
 }
 
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_PS(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0),
-                 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0))
-FOP_COND_PS(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status),
-                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status))
-FOP_COND_PS(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+ * but float32_unordered_quiet() is still called. */
+FOP_COND_PS(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
+                 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
+FOP_COND_PS(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
+FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_PS(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0),
-                 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0))
-FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status),
-                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status))
-FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+ * but float32_unordered() is still called. */
+FOP_COND_PS(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
+                 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
+FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
+FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
index 0f93e2abb10f1a331a29f059bcc25bff12ee5bca..4eaa8261c35fc1d49f18122d294a7e8d7d2aa637 100644 (file)
@@ -2686,7 +2686,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
         likely(!ctx->singlestep_enabled)) {
         tcg_gen_goto_tb(n);
         gen_save_pc(dest);
-        tcg_gen_exit_tb((long)tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         gen_save_pc(dest);
         if (ctx->singlestep_enabled) {
@@ -12737,8 +12737,7 @@ void cpu_reset (CPUMIPSState *env)
     env->exception_index = EXCP_NONE;
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->active_tc.PC = gen_opc_pc[pc_pos];
     env->hflags &= ~MIPS_HFLAG_BMASK;
index deb8d7c9c50c7832fb2ac63d71681929f4b05800..04b12590faecd367440bd76fc0bdbc2c81a23de3 100644 (file)
@@ -43,6 +43,8 @@
 # define TARGET_VIRT_ADDR_SPACE_BITS 64
 #endif
 
+#define TARGET_PAGE_BITS_16M 24
+
 #else /* defined (TARGET_PPC64) */
 /* PowerPC 32 definitions */
 #define TARGET_LONG_BITS 32
@@ -112,10 +114,13 @@ enum powerpc_mmu_t {
     POWERPC_MMU_601        = 0x0000000A,
 #if defined(TARGET_PPC64)
 #define POWERPC_MMU_64       0x00010000
+#define POWERPC_MMU_1TSEG    0x00020000
     /* 64 bits PowerPC MMU                                     */
     POWERPC_MMU_64B        = POWERPC_MMU_64 | 0x00000001,
     /* 620 variant (no segment exceptions)                     */
     POWERPC_MMU_620        = POWERPC_MMU_64 | 0x00000002,
+    /* Architecture 2.06 variant                               */
+    POWERPC_MMU_2_06       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
 #endif /* defined(TARGET_PPC64) */
 };
 
@@ -151,6 +156,8 @@ enum powerpc_excp_t {
 #if defined(TARGET_PPC64)
     /* PowerPC 970 exception model      */
     POWERPC_EXCP_970,
+    /* POWER7 exception model           */
+    POWERPC_EXCP_POWER7,
 #endif /* defined(TARGET_PPC64) */
 };
 
@@ -286,6 +293,8 @@ enum powerpc_input_t {
     PPC_FLAGS_INPUT_405,
     /* PowerPC 970 bus                  */
     PPC_FLAGS_INPUT_970,
+    /* PowerPC POWER7 bus               */
+    PPC_FLAGS_INPUT_POWER7,
     /* PowerPC 401 bus                  */
     PPC_FLAGS_INPUT_401,
     /* Freescale RCPU bus               */
@@ -357,12 +366,51 @@ union ppc_tlb_t {
 };
 #endif
 
+#define SDR_32_HTABORG         0xFFFF0000UL
+#define SDR_32_HTABMASK        0x000001FFUL
+
+#if defined(TARGET_PPC64)
+#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
+#define SDR_64_HTABSIZE        0x000000000000001FULL
+#endif /* defined(TARGET_PPC64 */
+
+#define HASH_PTE_SIZE_32       8
+#define HASH_PTE_SIZE_64       16
+
 typedef struct ppc_slb_t ppc_slb_t;
 struct ppc_slb_t {
-    uint64_t tmp64;
-    uint32_t tmp;
+    uint64_t esid;
+    uint64_t vsid;
 };
 
+/* Bits in the SLB ESID word */
+#define SLB_ESID_ESID           0xFFFFFFFFF0000000ULL
+#define SLB_ESID_V              0x0000000008000000ULL /* valid */
+
+/* Bits in the SLB VSID word */
+#define SLB_VSID_SHIFT          12
+#define SLB_VSID_SHIFT_1T       24
+#define SLB_VSID_SSIZE_SHIFT    62
+#define SLB_VSID_B              0xc000000000000000ULL
+#define SLB_VSID_B_256M         0x0000000000000000ULL
+#define SLB_VSID_B_1T           0x4000000000000000ULL
+#define SLB_VSID_VSID           0x3FFFFFFFFFFFF000ULL
+#define SLB_VSID_PTEM           (SLB_VSID_B | SLB_VSID_VSID)
+#define SLB_VSID_KS             0x0000000000000800ULL
+#define SLB_VSID_KP             0x0000000000000400ULL
+#define SLB_VSID_N              0x0000000000000200ULL /* no-execute */
+#define SLB_VSID_L              0x0000000000000100ULL
+#define SLB_VSID_C              0x0000000000000080ULL /* class */
+#define SLB_VSID_LP             0x0000000000000030ULL
+#define SLB_VSID_ATTR           0x0000000000000FFFULL
+
+#define SEGMENT_SHIFT_256M      28
+#define SEGMENT_MASK_256M       (~((1ULL << SEGMENT_SHIFT_256M) - 1))
+
+#define SEGMENT_SHIFT_1T        40
+#define SEGMENT_MASK_1T         (~((1ULL << SEGMENT_SHIFT_1T) - 1))
+
+
 /*****************************************************************************/
 /* Machine state register bits definition                                    */
 #define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
@@ -619,8 +667,11 @@ struct CPUPPCState {
     int slb_nr;
 #endif
     /* segment registers */
-    target_ulong sdr1;
+    target_phys_addr_t htab_base;
+    target_phys_addr_t htab_mask;
     target_ulong sr[32];
+    /* externally stored hash table */
+    uint8_t *external_htab;
     /* BATs */
     int nb_BATs;
     target_ulong DBAT[2][8];
@@ -670,6 +721,13 @@ struct CPUPPCState {
     uint32_t flags;
     uint64_t insns_flags;
 
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+    target_phys_addr_t vpa;
+    target_phys_addr_t slb_shadow;
+    target_phys_addr_t dispatch_trace_log;
+    uint32_t dtl_size;
+#endif /* TARGET_PPC64 */
+
     int error_code;
     uint32_t pending_interrupts;
 #if !defined(CONFIG_USER_ONLY)
@@ -712,7 +770,7 @@ struct mmu_ctx_t {
     target_phys_addr_t raddr;      /* Real address              */
     target_phys_addr_t eaddr;      /* Effective address         */
     int prot;                      /* Protection bits           */
-    target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
+    target_phys_addr_t hash[2];    /* Pagetable hash values     */
     target_ulong ptem;             /* Virtual segment ID | API  */
     int key;                       /* Access key                */
     int nx;                        /* Non-execute area          */
@@ -755,7 +813,9 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
 void ppc_store_asr (CPUPPCState *env, target_ulong value);
 target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr);
 target_ulong ppc_load_sr (CPUPPCState *env, int sr_nr);
-void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
+int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
+int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt);
+int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt);
 #endif /* defined(TARGET_PPC64) */
 void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value);
 #endif /* !defined(CONFIG_USER_ONLY) */
@@ -956,6 +1016,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #define SPR_HSPRG1            (0x131)
 #define SPR_HDSISR            (0x132)
 #define SPR_HDAR              (0x133)
+#define SPR_SPURR             (0x134)
 #define SPR_BOOKE_DBCR0       (0x134)
 #define SPR_IBCR              (0x135)
 #define SPR_PURR              (0x135)
@@ -1480,6 +1541,8 @@ enum {
     PPC_DCRX           = 0x2000000000000000ULL,
     /* user-mode DCR access, implemented in PowerPC 460                      */
     PPC_DCRUX          = 0x4000000000000000ULL,
+    /* popcntw and popcntd instructions                                      */
+    PPC_POPCNTWD       = 0x8000000000000000ULL,
 };
 
 /*****************************************************************************/
@@ -1578,6 +1641,15 @@ enum {
     PPC970_INPUT_THINT      = 6,
     PPC970_INPUT_NB,
 };
+
+enum {
+    /* POWER7 input pins */
+    POWER7_INPUT_INT        = 0,
+    /* POWER7 probably has other inputs, but we don't care about them
+     * for any existing machine.  We can wire these up when we need
+     * them */
+    POWER7_INPUT_NB,
+};
 #endif
 
 /* Hardware exceptions definitions */
@@ -1623,4 +1695,6 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
 #endif
 }
 
+extern void (*cpu_ppc_hypercall)(CPUState *);
+
 #endif /* !defined (__CPU_PPC_H__) */
index 4b491012d726cede9bd49ae5d267d0fbc1dcc459..5e4030bb531e8c7fad83237d0c89c0ce4c485a29 100644 (file)
 #  define LOG_EXCP(...) do { } while (0)
 #endif
 
+/*****************************************************************************/
+/* PowerPC Hypercall emulation */
+
+void (*cpu_ppc_hypercall)(CPUState *);
 
 /*****************************************************************************/
 /* PowerPC MMU emulation */
@@ -563,21 +567,35 @@ static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual,
     return ret;
 }
 
+static inline target_phys_addr_t get_pteg_offset(CPUState *env,
+                                                 target_phys_addr_t hash,
+                                                 int pte_size)
+{
+    return (hash * pte_size * 8) & env->htab_mask;
+}
+
 /* PTE table lookup */
-static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
-                            int type, int target_page_bits)
+static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
+                            int rw, int type, int target_page_bits)
 {
-    target_ulong base, pte0, pte1;
+    target_phys_addr_t pteg_off;
+    target_ulong pte0, pte1;
     int i, good = -1;
     int ret, r;
 
     ret = -1; /* No entry found */
-    base = ctx->pg_addr[h];
+    pteg_off = get_pteg_offset(env, ctx->hash[h],
+                               is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
     for (i = 0; i < 8; i++) {
 #if defined(TARGET_PPC64)
         if (is_64b) {
-            pte0 = ldq_phys(base + (i * 16));
-            pte1 = ldq_phys(base + (i * 16) + 8);
+            if (env->external_htab) {
+                pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
+                pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
+            } else {
+                pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
+                pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
+            }
 
             /* We have a TLB that saves 4K pages, so let's
              * split a huge page to 4k chunks */
@@ -588,17 +606,22 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
             r = pte64_check(ctx, pte0, pte1, h, rw, type);
             LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
                     TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
-                    base + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
+                    pteg_base + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
                     (int)((pte0 >> 1) & 1), ctx->ptem);
         } else
 #endif
         {
-            pte0 = ldl_phys(base + (i * 8));
-            pte1 =  ldl_phys(base + (i * 8) + 4);
+            if (env->external_htab) {
+                pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
+                pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
+            } else {
+                pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
+                pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
+            }
             r = pte32_check(ctx, pte0, pte1, h, rw, type);
             LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
                     TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
-                    base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
+                    pteg_base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
                     (int)((pte0 >> 6) & 1), ctx->ptem);
         }
         switch (r) {
@@ -634,11 +657,23 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
         if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
 #if defined(TARGET_PPC64)
             if (is_64b) {
-                stq_phys_notdirty(base + (good * 16) + 8, pte1);
+                if (env->external_htab) {
+                    stq_p(env->external_htab + pteg_off + (good * 16) + 8,
+                          pte1);
+                } else {
+                    stq_phys_notdirty(env->htab_base + pteg_off +
+                                      (good * 16) + 8, pte1);
+                }
             } else
 #endif
             {
-                stl_phys_notdirty(base + (good * 8) + 4, pte1);
+                if (env->external_htab) {
+                    stl_p(env->external_htab + pteg_off + (good * 8) + 4,
+                          pte1);
+                } else {
+                    stl_phys_notdirty(env->htab_base + pteg_off +
+                                      (good * 8) + 4, pte1);
+                }
             }
         }
     }
@@ -646,111 +681,45 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
     return ret;
 }
 
-static inline int find_pte32(mmu_ctx_t *ctx, int h, int rw, int type,
-                             int target_page_bits)
-{
-    return _find_pte(ctx, 0, h, rw, type, target_page_bits);
-}
-
-#if defined(TARGET_PPC64)
-static inline int find_pte64(mmu_ctx_t *ctx, int h, int rw, int type,
-                             int target_page_bits)
-{
-    return _find_pte(ctx, 1, h, rw, type, target_page_bits);
-}
-#endif
-
 static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
                            int type, int target_page_bits)
 {
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64)
-        return find_pte64(ctx, h, rw, type, target_page_bits);
+        return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
 #endif
 
-    return find_pte32(ctx, h, rw, type, target_page_bits);
+    return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
 }
 
 #if defined(TARGET_PPC64)
-static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr)
-{
-    ppc_slb_t *retval = &env->slb[nr];
-
-#if 0 // XXX implement bridge mode?
-    if (env->spr[SPR_ASR] & 1) {
-        target_phys_addr_t sr_base;
-
-        sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000;
-        sr_base += (12 * nr);
-
-        retval->tmp64 = ldq_phys(sr_base);
-        retval->tmp = ldl_phys(sr_base + 8);
-    }
-#endif
-
-    return retval;
-}
-
-static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb)
+static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
 {
-    ppc_slb_t *entry = &env->slb[nr];
-
-    if (slb == entry)
-        return;
-
-    entry->tmp64 = slb->tmp64;
-    entry->tmp = slb->tmp;
-}
-
-static inline int slb_is_valid(ppc_slb_t *slb)
-{
-    return (int)(slb->tmp64 & 0x0000000008000000ULL);
-}
+    uint64_t esid_256M, esid_1T;
+    int n;
 
-static inline void slb_invalidate(ppc_slb_t *slb)
-{
-    slb->tmp64 &= ~0x0000000008000000ULL;
-}
+    LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
 
-static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr,
-                             target_ulong *vsid, target_ulong *page_mask,
-                             int *attr, int *target_page_bits)
-{
-    target_ulong mask;
-    int n, ret;
+    esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+    esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
 
-    ret = -5;
-    LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
-    mask = 0x0000000000000000ULL; /* Avoid gcc warning */
     for (n = 0; n < env->slb_nr; n++) {
-        ppc_slb_t *slb = slb_get_entry(env, n);
-
-        LOG_SLB("%s: seg %d %016" PRIx64 " %08"
-                    PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
-        if (slb_is_valid(slb)) {
-            /* SLB entry is valid */
-            mask = 0xFFFFFFFFF0000000ULL;
-            if (slb->tmp & 0x8) {
-                /* 16 MB PTEs */
-                if (target_page_bits)
-                    *target_page_bits = 24;
-            } else {
-                /* 4 KB PTEs */
-                if (target_page_bits)
-                    *target_page_bits = TARGET_PAGE_BITS;
-            }
-            if ((eaddr & mask) == (slb->tmp64 & mask)) {
-                /* SLB match */
-                *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
-                *page_mask = ~mask;
-                *attr = slb->tmp & 0xFF;
-                ret = n;
-                break;
-            }
+        ppc_slb_t *slb = &env->slb[n];
+
+        LOG_SLB("%s: slot %d %016" PRIx64 " %016"
+                    PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
+        /* We check for 1T matches on all MMUs here - if the MMU
+         * doesn't have 1T segment support, we will have prevented 1T
+         * entries from being inserted in the slbmte code. */
+        if (((slb->esid == esid_256M) &&
+             ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
+            || ((slb->esid == esid_1T) &&
+                ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
+            return slb;
         }
     }
 
-    return ret;
+    return NULL;
 }
 
 void ppc_slb_invalidate_all (CPUPPCState *env)
@@ -760,11 +729,10 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
     do_invalidate = 0;
     /* XXX: Warning: slbia never invalidates the first segment */
     for (n = 1; n < env->slb_nr; n++) {
-        ppc_slb_t *slb = slb_get_entry(env, n);
+        ppc_slb_t *slb = &env->slb[n];
 
-        if (slb_is_valid(slb)) {
-            slb_invalidate(slb);
-            slb_set_entry(env, n, slb);
+        if (slb->esid & SLB_ESID_V) {
+            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
@@ -778,131 +746,145 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
 
 void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
 {
-    target_ulong vsid, page_mask;
-    int attr;
-    int n;
+    ppc_slb_t *slb;
 
-    n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
-    if (n >= 0) {
-        ppc_slb_t *slb = slb_get_entry(env, n);
+    slb = slb_lookup(env, T0);
+    if (!slb) {
+        return;
+    }
 
-        if (slb_is_valid(slb)) {
-            slb_invalidate(slb);
-            slb_set_entry(env, n, slb);
-            /* 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
-             */
-            tlb_flush(env, 1);
-        }
+    if (slb->esid & SLB_ESID_V) {
+        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
+         */
+        tlb_flush(env, 1);
     }
 }
 
-target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
+int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
 {
-    target_ulong rt;
-    ppc_slb_t *slb = slb_get_entry(env, slb_nr);
+    int slot = rb & 0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
 
-    if (slb_is_valid(slb)) {
-        /* SLB entry is valid */
-        /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
-        rt = slb->tmp >> 8;             /* 65:88 => 40:63 */
-        rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
-        /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
-        rt |= ((slb->tmp >> 4) & 0xF) << 27;
-    } else {
-        rt = 0;
+    if (rb & (0x1000 - env->slb_nr)) {
+        return -1; /* Reserved bits set or slot too high */
+    }
+    if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
+        return -1; /* Bad segment size */
+    }
+    if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
+        return -1; /* 1T segment on MMU that doesn't support it */
     }
-    LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
-            TARGET_FMT_lx "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
 
-    return rt;
+    /* Mask out the slot number as we store the entry */
+    slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
+    slb->vsid = rs;
+
+    LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
+            " %016" PRIx64 "\n", __func__, slot, rb, rs,
+            slb->esid, slb->vsid);
+
+    return 0;
 }
 
-void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
+int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
 {
-    ppc_slb_t *slb;
-
-    uint64_t vsid;
-    uint64_t esid;
-    int flags, valid, slb_nr;
+    int slot = rb & 0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
 
-    vsid = rs >> 12;
-    flags = ((rs >> 8) & 0xf);
+    if (slot >= env->slb_nr) {
+        return -1;
+    }
 
-    esid = rb >> 28;
-    valid = (rb & (1 << 27));
-    slb_nr = rb & 0xfff;
+    *rt = slb->esid;
+    return 0;
+}
 
-    slb = slb_get_entry(env, slb_nr);
-    slb->tmp64 = (esid << 28) | valid | (vsid >> 24);
-    slb->tmp = (vsid << 8) | (flags << 3);
+int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
+{
+    int slot = rb & 0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
 
-    LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
-            " %08" PRIx32 "\n", __func__, slb_nr, rb, rs, slb->tmp64,
-            slb->tmp);
+    if (slot >= env->slb_nr) {
+        return -1;
+    }
 
-    slb_set_entry(env, slb_nr, slb);
+    *rt = slb->vsid;
+    return 0;
 }
 #endif /* defined(TARGET_PPC64) */
 
 /* Perform segment based translation */
-static inline target_phys_addr_t get_pgaddr(target_phys_addr_t sdr1,
-                                            int sdr_sh,
-                                            target_phys_addr_t hash,
-                                            target_phys_addr_t mask)
-{
-    return (sdr1 & ((target_phys_addr_t)(-1ULL) << sdr_sh)) | (hash & mask);
-}
-
 static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                               target_ulong eaddr, int rw, int type)
 {
-    target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
-    target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
-#if defined(TARGET_PPC64)
-    int attr;
-#endif
-    int ds, vsid_sh, sdr_sh, pr, target_page_bits;
+    target_phys_addr_t hash;
+    target_ulong vsid;
+    int ds, pr, target_page_bits;
     int ret, ret2;
 
     pr = msr_pr;
+    ctx->eaddr = eaddr;
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64) {
+        ppc_slb_t *slb;
+        target_ulong pageaddr;
+        int segment_bits;
+
         LOG_MMU("Check SLBs\n");
-        ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr,
-                         &target_page_bits);
-        if (ret < 0)
-            return ret;
-        ctx->key = ((attr & 0x40) && (pr != 0)) ||
-            ((attr & 0x80) && (pr == 0)) ? 1 : 0;
+        slb = slb_lookup(env, eaddr);
+        if (!slb) {
+            return -5;
+        }
+
+        if (slb->vsid & SLB_VSID_B) {
+            vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
+            segment_bits = 40;
+        } else {
+            vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+            segment_bits = 28;
+        }
+
+        target_page_bits = (slb->vsid & SLB_VSID_L)
+            ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+        ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
+                      : (slb->vsid & SLB_VSID_KS));
         ds = 0;
-        ctx->nx = attr & 0x10 ? 1 : 0;
-        ctx->eaddr = eaddr;
-        vsid_mask = 0x00003FFFFFFFFF80ULL;
-        vsid_sh = 7;
-        sdr_sh = 18;
-        sdr_mask = 0x3FF80;
+        ctx->nx = !!(slb->vsid & SLB_VSID_N);
+
+        pageaddr = eaddr & ((1ULL << segment_bits)
+                            - (1ULL << target_page_bits));
+        if (slb->vsid & SLB_VSID_B) {
+            hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
+        } else {
+            hash = vsid ^ (pageaddr >> target_page_bits);
+        }
+        /* Only 5 bits of the page index are used in the AVPN */
+        ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
+            ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
     } else
 #endif /* defined(TARGET_PPC64) */
     {
+        target_ulong sr, pgidx;
+
         sr = env->sr[eaddr >> 28];
-        page_mask = 0x0FFFFFFF;
         ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
                     ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
         ds = sr & 0x80000000 ? 1 : 0;
         ctx->nx = sr & 0x10000000 ? 1 : 0;
         vsid = sr & 0x00FFFFFF;
-        vsid_mask = 0x01FFFFC0;
-        vsid_sh = 6;
-        sdr_sh = 16;
-        sdr_mask = 0xFFC0;
         target_page_bits = TARGET_PAGE_BITS;
         LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
                 TARGET_FMT_lx " lr=" TARGET_FMT_lx
                 " ir=%d dr=%d pr=%d %d t=%d\n",
                 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
                 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+        pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+        hash = vsid ^ pgidx;
+        ctx->ptem = (vsid << 7) | (pgidx >> 10);
     }
     LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
             ctx->key, ds, ctx->nx, vsid);
@@ -911,44 +893,12 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         /* Check if instruction fetch is allowed, if needed */
         if (type != ACCESS_CODE || ctx->nx == 0) {
             /* Page address translation */
-            /* Primary table address */
-            sdr = env->sdr1;
-            pgidx = (eaddr & page_mask) >> target_page_bits;
-#if defined(TARGET_PPC64)
-            if (env->mmu_model & POWERPC_MMU_64) {
-                htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
-                /* XXX: this is false for 1 TB segments */
-                hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
-            } else
-#endif
-            {
-                htab_mask = sdr & 0x000001FF;
-                hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
-            }
-            mask = (htab_mask << sdr_sh) | sdr_mask;
-            LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx
-                    " mask " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
-                    sdr, sdr_sh, hash, mask, page_mask);
-            ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask);
-            /* Secondary table address */
-            hash = (~hash) & vsid_mask;
-            LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx
-                    " mask " TARGET_FMT_plx "\n", sdr, sdr_sh, hash, mask);
-            ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask);
-#if defined(TARGET_PPC64)
-            if (env->mmu_model & POWERPC_MMU_64) {
-                /* Only 5 bits of the page index are used in the AVPN */
-                if (target_page_bits > 23) {
-                    ctx->ptem = (vsid << 12) |
-                                ((pgidx << (target_page_bits - 16)) & 0xF80);
-                } else {
-                    ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80);
-                }
-            } else
-#endif
-            {
-                ctx->ptem = (vsid << 7) | (pgidx >> 10);
-            }
+            LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+                    " hash " TARGET_FMT_plx "\n",
+                    env->htab_base, env->htab_mask, hash);
+            ctx->hash[0] = hash;
+            ctx->hash[1] = ~hash;
+
             /* Initialize real address with an invalid value */
             ctx->raddr = (target_phys_addr_t)-1ULL;
             if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
@@ -956,19 +906,21 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                 /* Software TLB search */
                 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
             } else {
-                LOG_MMU("0 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " "
-                        "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx
-                        " pg_addr=" TARGET_FMT_plx "\n",
-                        sdr, vsid, pgidx, hash, ctx->pg_addr[0]);
+                LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+                        " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+                        " hash=" TARGET_FMT_plx "\n",
+                        env->htab_base, env->htab_mask, vsid, ctx->ptem,
+                        ctx->hash[0]);
                 /* Primary table lookup */
                 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
                 if (ret < 0) {
                     /* Secondary table lookup */
                     if (eaddr != 0xEFFFFFFF)
-                        LOG_MMU("1 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " "
-                                "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx
-                                " pg_addr=" TARGET_FMT_plx "\n", sdr, vsid,
-                                pgidx, hash, ctx->pg_addr[1]);
+                        LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+                                " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+                                " hash=" TARGET_FMT_plx " pg_addr="
+                                TARGET_FMT_plx "\n", env->htab_base,
+                                env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
                     ret2 = find_pte(env, ctx, 1, rw, type,
                                     target_page_bits);
                     if (ret2 != -1)
@@ -1268,6 +1220,7 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_620:
     case POWERPC_MMU_64B:
+    case POWERPC_MMU_2_06:
         /* Real address are 60 bits long */
         ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
         ctx->prot |= PAGE_WRITE;
@@ -1345,6 +1298,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
 #if defined(TARGET_PPC64)
         case POWERPC_MMU_620:
         case POWERPC_MMU_64B:
+        case POWERPC_MMU_2_06:
 #endif
             if (ret < 0) {
                 /* We didn't match any BAT entry or don't have BATs */
@@ -1444,6 +1398,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 #if defined(TARGET_PPC64)
                 case POWERPC_MMU_620:
                 case POWERPC_MMU_64B:
+                case POWERPC_MMU_2_06:
 #endif
                     env->exception_index = POWERPC_EXCP_ISI;
                     env->error_code = 0x40000000;
@@ -1520,8 +1475,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                     env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
                 tlb_miss:
                     env->error_code |= ctx.key << 19;
-                    env->spr[SPR_HASH1] = ctx.pg_addr[0];
-                    env->spr[SPR_HASH2] = ctx.pg_addr[1];
+                    env->spr[SPR_HASH1] = env->htab_base +
+                        get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
+                    env->spr[SPR_HASH2] = env->htab_base +
+                        get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
                     break;
                 case POWERPC_MMU_SOFT_74xx:
                     if (rw == 1) {
@@ -1551,6 +1508,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 #if defined(TARGET_PPC64)
                 case POWERPC_MMU_620:
                 case POWERPC_MMU_64B:
+                case POWERPC_MMU_2_06:
 #endif
                     env->exception_index = POWERPC_EXCP_DSI;
                     env->error_code = 0;
@@ -1874,6 +1832,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_620:
     case POWERPC_MMU_64B:
+    case POWERPC_MMU_2_06:
 #endif /* defined(TARGET_PPC64) */
         tlb_flush(env, 1);
         break;
@@ -1941,6 +1900,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_620:
     case POWERPC_MMU_64B:
+    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,
@@ -1974,11 +1934,26 @@ void ppc_store_asr (CPUPPCState *env, target_ulong value)
 void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
 {
     LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
-    if (env->sdr1 != value) {
-        /* XXX: for PowerPC 64, should check that the HTABSIZE value
-         *      is <= 28
-         */
-        env->sdr1 = value;
+    if (env->spr[SPR_SDR1] != value) {
+        env->spr[SPR_SDR1] = value;
+#if defined(TARGET_PPC64)
+        if (env->mmu_model & POWERPC_MMU_64) {
+            target_ulong htabsize = value & SDR_64_HTABSIZE;
+
+            if (htabsize > 28) {
+                fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
+                        " stored in SDR1\n", htabsize);
+                htabsize = 28;
+            }
+            env->htab_mask = (1ULL << (htabsize + 18)) - 1;
+            env->htab_base = value & SDR_64_HTABORG;
+        } else
+#endif /* defined(TARGET_PPC64) */
+        {
+            /* FIXME: Should check for valid HTABMASK values */
+            env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
+            env->htab_base = value & SDR_32_HTABORG;
+        }
         tlb_flush(env, 1);
     }
 }
@@ -2228,6 +2203,10 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
         dump_syscall(env);
         lev = env->error_code;
+        if ((lev == 1) && cpu_ppc_hypercall) {
+            cpu_ppc_hypercall(env);
+            return;
+        }
         if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
             new_msr |= (target_ulong)MSR_HVB;
         goto store_next;
index 2bf9283486c8ef684947e5c2ad5751a824088555..7c02be9cfdc7c4e39d025611c74af7f2456770f5 100644 (file)
@@ -38,10 +38,11 @@ DEF_HELPER_2(mulldo, i64, i64, i64)
 
 DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 DEF_HELPER_2(sraw, tl, tl, tl)
 #if defined(TARGET_PPC64)
 DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
-DEF_HELPER_FLAGS_1(popcntb_64, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 DEF_HELPER_2(srad, tl, tl, tl)
 #endif
 
@@ -340,8 +341,9 @@ DEF_HELPER_1(74xx_tlbi, void, tl)
 DEF_HELPER_FLAGS_0(tlbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(tlbie, TCG_CALL_CONST, void, tl)
 #if defined(TARGET_PPC64)
-DEF_HELPER_FLAGS_1(load_slb, TCG_CALL_CONST, tl, tl)
 DEF_HELPER_FLAGS_2(store_slb, TCG_CALL_CONST, void, tl, tl)
+DEF_HELPER_1(load_slb_esid, tl, tl)
+DEF_HELPER_1(load_slb_vsid, tl, tl)
 DEF_HELPER_FLAGS_0(slbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(slbie, TCG_CALL_CONST, void, tl)
 #endif
@@ -375,6 +377,7 @@ DEF_HELPER_0(load_601_rtcu, tl)
 #if !defined(CONFIG_USER_ONLY)
 #if defined(TARGET_PPC64)
 DEF_HELPER_1(store_asr, void, tl)
+DEF_HELPER_0(load_purr, tl)
 #endif
 DEF_HELPER_1(store_sdr1, void, tl)
 DEF_HELPER_1(store_tbl, void, tl)
index 0e2e67b34d6193053d4482d7a68a172fa54b9540..2cfb24bb1de2a26e2443b0ac1cd71e0c5c1a15c0 100644 (file)
@@ -169,7 +169,7 @@ int kvm_arch_get_registers(CPUState *env)
 
 #ifdef KVM_CAP_PPC_SEGSTATE
     if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_SEGSTATE)) {
-        env->sdr1 = sregs.u.s.sdr1;
+        ppc_store_sdr1(env, sregs.u.s.sdr1);
 
         /* Sync SLB */
 #ifdef TARGET_PPC64
index 911b19e378b499a1a4b5d8381c1aa5e8640e2cc6..45a1373b28130aa1f15ee256d862b82a0c2aa985 100644 (file)
 
 void kvmppc_init(void);
 void kvmppc_fdt_update(void *fdt);
+#ifndef CONFIG_KVM
+static inline int kvmppc_read_host_property(const char *node_path, const char *prop,
+                                            void *val, size_t len)
+{
+    assert(0);
+    return -ENOSYS;
+}
+#else
 int kvmppc_read_host_property(const char *node_path, const char *prop,
                                      void *val, size_t len);
+#endif
 
 uint32_t kvmppc_get_tbfreq(void);
 int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
 int kvmppc_set_interrupt(CPUState *env, int irq, int level);
 
+#ifndef CONFIG_KVM
+#define kvmppc_eieio() do { } while (0)
+#else
+#define kvmppc_eieio() \
+    do {                                          \
+        if (kvm_enabled()) {                          \
+            asm volatile("eieio" : : : "memory"); \
+        } \
+    } while (0)
+#endif
+
 #ifndef KVM_INTERRUPT_SET
 #define KVM_INTERRUPT_SET -1
 #endif
index 67de951959aa01d605d9a7b7e0b705deb1be348a..0c1986e528dc21db51f28d962dfba74fa429f8b7 100644 (file)
@@ -37,7 +37,7 @@ void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_betls(f, &env->asr);
     qemu_put_sbe32s(f, &env->slb_nr);
 #endif
-    qemu_put_betls(f, &env->sdr1);
+    qemu_put_betls(f, &env->spr[SPR_SDR1]);
     for (i = 0; i < 32; i++)
         qemu_put_betls(f, &env->sr[i]);
     for (i = 0; i < 2; i++)
@@ -93,6 +93,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 {
     CPUState *env = (CPUState *)opaque;
     unsigned int i, j;
+    target_ulong sdr1;
 
     for (i = 0; i < 32; i++)
         qemu_get_betls(f, &env->gpr[i]);
@@ -124,7 +125,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     qemu_get_betls(f, &env->asr);
     qemu_get_sbe32s(f, &env->slb_nr);
 #endif
-    qemu_get_betls(f, &env->sdr1);
+    qemu_get_betls(f, &sdr1);
     for (i = 0; i < 32; i++)
         qemu_get_betls(f, &env->sr[i]);
     for (i = 0; i < 2; i++)
@@ -152,6 +153,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 #endif
     for (i = 0; i < 1024; i++)
         qemu_get_betls(f, &env->spr[i]);
+    ppc_store_sdr1(env, sdr1);
     qemu_get_be32s(f, &env->vscr);
     qemu_get_be64s(f, &env->spe_acc);
     qemu_get_be32s(f, &env->spe_fscr);
index 17e070ae75caa265e994743ccf44404d4de10373..d5db484b4aa755e3afe628d4c91ce1f62c2c25db 100644 (file)
@@ -86,6 +86,13 @@ target_ulong helper_load_atbu (void)
     return cpu_ppc_load_atbu(env);
 }
 
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+target_ulong helper_load_purr (void)
+{
+    return (target_ulong)cpu_ppc_load_purr(env);
+}
+#endif
+
 target_ulong helper_load_601_rtcl (void)
 {
     return cpu_ppc601_load_rtcl(env);
@@ -492,6 +499,38 @@ target_ulong helper_srad (target_ulong value, target_ulong shift)
 }
 #endif
 
+#if defined(TARGET_PPC64)
+target_ulong helper_popcntb (target_ulong val)
+{
+    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
+                                           0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
+                                           0x3333333333333333ULL);
+    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
+                                           0x0f0f0f0f0f0f0f0fULL);
+    return val;
+}
+
+target_ulong helper_popcntw (target_ulong val)
+{
+    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
+                                           0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
+                                           0x3333333333333333ULL);
+    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
+                                           0x0f0f0f0f0f0f0f0fULL);
+    val = (val & 0x00ff00ff00ff00ffULL) + ((val >>  8) &
+                                           0x00ff00ff00ff00ffULL);
+    val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
+                                           0x0000ffff0000ffffULL);
+    return val;
+}
+
+target_ulong helper_popcntd (target_ulong val)
+{
+    return ctpop64(val);
+}
+#else
 target_ulong helper_popcntb (target_ulong val)
 {
     val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
@@ -500,12 +539,13 @@ target_ulong helper_popcntb (target_ulong val)
     return val;
 }
 
-#if defined(TARGET_PPC64)
-target_ulong helper_popcntb_64 (target_ulong val)
+target_ulong helper_popcntw (target_ulong val)
 {
-    val = (val & 0x5555555555555555ULL) + ((val >>  1) & 0x5555555555555555ULL);
-    val = (val & 0x3333333333333333ULL) + ((val >>  2) & 0x3333333333333333ULL);
-    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) & 0x0f0f0f0f0f0f0f0fULL);
+    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
+    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
+    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
+    val = (val & 0x00ff00ff) + ((val >>  8) & 0x00ff00ff);
+    val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
     return val;
 }
 #endif
@@ -1247,7 +1287,6 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
             /* sNaN operation */
             fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
         }
-#ifdef FLOAT128
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
 
@@ -1263,10 +1302,6 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
             ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
             farg1.d = float128_to_float64(ft0_128, &env->fp_status);
         }
-#else
-        /* This is OK on x86 hosts */
-        farg1.d = (farg1.d * farg2.d) + farg3.d;
-#endif
     }
 
     return farg1.ll;
@@ -1292,7 +1327,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
             /* sNaN operation */
             fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
         }
-#ifdef FLOAT128
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
 
@@ -1308,10 +1342,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
             ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
             farg1.d = float128_to_float64(ft0_128, &env->fp_status);
         }
-#else
-        /* This is OK on x86 hosts */
-        farg1.d = (farg1.d * farg2.d) - farg3.d;
-#endif
     }
     return farg1.ll;
 }
@@ -1336,7 +1366,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
             /* sNaN operation */
             fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
         }
-#ifdef FLOAT128
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
 
@@ -1352,10 +1381,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
             ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
             farg1.d = float128_to_float64(ft0_128, &env->fp_status);
         }
-#else
-        /* This is OK on x86 hosts */
-        farg1.d = (farg1.d * farg2.d) + farg3.d;
-#endif
         if (likely(!float64_is_any_nan(farg1.d))) {
             farg1.d = float64_chs(farg1.d);
         }
@@ -1383,7 +1408,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
             /* sNaN operation */
             fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
         }
-#ifdef FLOAT128
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
 
@@ -1399,10 +1423,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
             ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
             farg1.d = float128_to_float64(ft0_128, &env->fp_status);
         }
-#else
-        /* This is OK on x86 hosts */
-        farg1.d = (farg1.d * farg2.d) - farg3.d;
-#endif
         if (likely(!float64_is_any_nan(farg1.d))) {
             farg1.d = float64_chs(farg1.d);
         }
@@ -3323,7 +3343,7 @@ HELPER_SPE_VECTOR_ARITH(fsmul);
 HELPER_SPE_VECTOR_ARITH(fsdiv);
 
 /* Single-precision floating-point comparisons */
-static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
+static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
 {
     CPU_FloatU u1, u2;
     u1.l = op1;
@@ -3331,7 +3351,7 @@ static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
     return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
 }
 
-static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
+static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
 {
     CPU_FloatU u1, u2;
     u1.l = op1;
@@ -3339,7 +3359,7 @@ static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
     return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
 }
 
-static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
+static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
 {
     CPU_FloatU u1, u2;
     u1.l = op1;
@@ -3347,22 +3367,22 @@ static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
     return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
 }
 
-static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
+static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
 {
-    /* XXX: TODO: test special values (NaN, infinites, ...) */
-    return efststlt(op1, op2);
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmplt(op1, op2);
 }
 
-static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
+static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
 {
-    /* XXX: TODO: test special values (NaN, infinites, ...) */
-    return efststgt(op1, op2);
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmpgt(op1, op2);
 }
 
-static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
+static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
 {
-    /* XXX: TODO: test special values (NaN, infinites, ...) */
-    return efststeq(op1, op2);
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmpeq(op1, op2);
 }
 
 #define HELPER_SINGLE_SPE_CMP(name)                                           \
@@ -3658,7 +3678,7 @@ uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
     CPU_DoubleU u1, u2;
     u1.ll = op1;
     u2.ll = op2;
-    return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
+    return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
 }
 
 uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
@@ -3721,7 +3741,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         helper_raise_exception_err(env->exception_index, env->error_code);
@@ -3746,14 +3766,31 @@ void helper_store_sr (target_ulong sr_num, target_ulong val)
 
 /* SLB management */
 #if defined(TARGET_PPC64)
-target_ulong helper_load_slb (target_ulong slb_nr)
+void helper_store_slb (target_ulong rb, target_ulong rs)
 {
-    return ppc_load_slb(env, slb_nr);
+    if (ppc_store_slb(env, rb, rs) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
 }
 
-void helper_store_slb (target_ulong rb, target_ulong rs)
+target_ulong helper_load_slb_esid (target_ulong rb)
 {
-    ppc_store_slb(env, rb, rs);
+    target_ulong rt;
+
+    if (ppc_load_slb_esid(env, rb, &rt) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+    return rt;
+}
+
+target_ulong helper_load_slb_vsid (target_ulong rb)
+{
+    target_ulong rt;
+
+    if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+    return rt;
 }
 
 void helper_slbia (void)
index 3d265e3b1162f5190e052c9ceba659a7238c872b..a943dbcf8e2bf66b2f7ca9d40527f1f32f86b863 100644 (file)
@@ -1483,13 +1483,21 @@ static void gen_xoris(DisasContext *ctx)
 /* popcntb : PowerPC 2.03 specification */
 static void gen_popcntb(DisasContext *ctx)
 {
+    gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+}
+
+static void gen_popcntw(DisasContext *ctx)
+{
+    gen_helper_popcntw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+}
+
 #if defined(TARGET_PPC64)
-    if (ctx->sf_mode)
-        gen_helper_popcntb_64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
-    else
-#endif
-        gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+/* popcntd: PowerPC 2.06 specification */
+static void gen_popcntd(DisasContext *ctx)
+{
+    gen_helper_popcntd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
 }
+#endif
 
 #if defined(TARGET_PPC64)
 /* extsw & extsw. */
@@ -3339,7 +3347,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
         likely(!ctx->singlestep_enabled)) {
         tcg_gen_goto_tb(n);
         tcg_gen_movi_tl(cpu_nip, dest & ~3);
-        tcg_gen_exit_tb((long)tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         tcg_gen_movi_tl(cpu_nip, dest & ~3);
         if (unlikely(ctx->singlestep_enabled)) {
@@ -4227,6 +4235,33 @@ static void gen_slbmte(DisasContext *ctx)
 #endif
 }
 
+static void gen_slbmfee(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)],
+                             cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+static void gen_slbmfev(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)],
+                             cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
 #endif /* defined(TARGET_PPC64) */
 
 /***                      Lookaside buffer management                      ***/
@@ -6975,7 +7010,7 @@ static inline void gen_evmergelo(DisasContext *ctx)
 #if defined(TARGET_PPC64)
     TCGv t0 = tcg_temp_new();
     TCGv t1 = tcg_temp_new();
-    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL);
+    tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
     tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32);
     tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
@@ -6994,7 +7029,7 @@ static inline void gen_evmergehilo(DisasContext *ctx)
 #if defined(TARGET_PPC64)
     TCGv t0 = tcg_temp_new();
     TCGv t1 = tcg_temp_new();
-    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL);
+    tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
     tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL);
     tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
@@ -7083,14 +7118,14 @@ static inline void gen_evsel(DisasContext *ctx)
     tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2);
     tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3);
 #if defined(TARGET_PPC64)
-    tcg_gen_andi_tl(t2, cpu_gpr[rA(ctx->opcode)], 0x00000000FFFFFFFFULL);
+    tcg_gen_ext32u_tl(t2, cpu_gpr[rA(ctx->opcode)]);
 #else
     tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
 #endif
     tcg_gen_br(l4);
     gen_set_label(l3);
 #if defined(TARGET_PPC64)
-    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFULL);
+    tcg_gen_ext32u_tl(t2, cpu_gpr[rB(ctx->opcode)]);
 #else
     tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
 #endif
@@ -8199,7 +8234,9 @@ GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
 GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
 GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
 GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB),
+GEN_HANDLER(popcntw, 0x1F, 0x1A, 0x0b, 0x0000F801, PPC_POPCNTWD),
 #if defined(TARGET_PPC64)
+GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
 GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
 #endif
 GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
@@ -8300,7 +8337,9 @@ GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
 GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B),
 GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
              PPC_SEGMENT_64B),
-GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x00000000, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x001F0001, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B),
 #endif
 GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA),
 GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x03FF0001, PPC_MEM_TLBIE),
@@ -9087,7 +9126,7 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
 #if !defined(CONFIG_USER_ONLY)
     cpu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx " SDR1 "
                 TARGET_FMT_lx "\n", env->spr[SPR_SRR0], env->spr[SPR_SRR1],
-                env->sdr1);
+                env->spr[SPR_SDR1]);
 #endif
 
 #undef RGPL
@@ -9328,8 +9367,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->nip = gen_opc_pc[pc_pos];
 }
index 7c08b1cb0904c2708fa5476ce8394887d23d29fb..e2a83c5a3875cd5c5eecf6947ae10fdf5d6c1d52 100644 (file)
@@ -61,6 +61,7 @@ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env);
 PPC_IRQ_INIT_FN(40x);
 PPC_IRQ_INIT_FN(6xx);
 PPC_IRQ_INIT_FN(970);
+PPC_IRQ_INIT_FN(POWER7);
 PPC_IRQ_INIT_FN(e500);
 
 /* Generic callbacks:
@@ -251,6 +252,14 @@ static void spr_write_atbu (void *opaque, int sprn, int gprn)
 {
     gen_helper_store_atbu(cpu_gpr[gprn]);
 }
+
+#if defined(TARGET_PPC64)
+__attribute__ (( unused ))
+static void spr_read_purr (void *opaque, int gprn, int sprn)
+{
+    gen_helper_load_purr(cpu_gpr[gprn]);
+}
+#endif
 #endif
 
 #if !defined(CONFIG_USER_ONLY)
@@ -335,11 +344,6 @@ static void spr_write_dbatl_h (void *opaque, int sprn, int gprn)
 }
 
 /* SDR1 */
-static void spr_read_sdr1 (void *opaque, int gprn, int sprn)
-{
-    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, sdr1));
-}
-
 static void spr_write_sdr1 (void *opaque, int sprn, int gprn)
 {
     gen_helper_store_sdr1(cpu_gpr[gprn]);
@@ -663,7 +667,7 @@ static void gen_spr_ne_601 (CPUPPCState *env)
     /* Memory management */
     spr_register(env, SPR_SDR1, "SDR1",
                  SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_sdr1, &spr_write_sdr1,
+                 &spr_read_generic, &spr_write_sdr1,
                  0x00000000);
 }
 
@@ -3128,6 +3132,35 @@ static void init_excp_970 (CPUPPCState *env)
     env->hreset_vector = 0x0000000000000100ULL;
 #endif
 }
+
+static void init_excp_POWER7 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_MAINT]    = 0x00001600;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001700;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001800;
+    env->hreset_excp_prefix = 0;
+    /* Hardware reset vector */
+    env->hreset_vector = 0x0000000000000100ULL;
+#endif
+}
 #endif
 
 /*****************************************************************************/
@@ -6309,6 +6342,78 @@ static void init_proc_970MP (CPUPPCState *env)
     vscr_init(env, 0x00010000);
 }
 
+#if defined(TARGET_PPC64)
+/* POWER7 */
+#define POWERPC_INSNS_POWER7  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT |  \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_SEGMENT_64B | PPC_SLBI |                    \
+                              PPC_POPCNTB | PPC_POPCNTWD)
+#define POWERPC_MSRM_POWER7   (0x800000000204FF36ULL)
+#define POWERPC_MMU_POWER7    (POWERPC_MMU_2_06)
+#define POWERPC_EXCP_POWER7   (POWERPC_EXCP_POWER7)
+#define POWERPC_INPUT_POWER7  (PPC_FLAGS_INPUT_POWER7)
+#define POWERPC_BFDM_POWER7   (bfd_mach_ppc64)
+#define POWERPC_FLAG_POWER7   (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_POWER7    check_pow_nocheck
+
+static void init_proc_POWER7 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+#if !defined(CONFIG_USER_ONLY)
+    /* PURR & SPURR: Hack - treat these as aliases for the TB for now */
+    spr_register(env, SPR_PURR,   "PURR",
+                 &spr_read_purr, SPR_NOACCESS,
+                 &spr_read_purr, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPURR,   "SPURR",
+                 &spr_read_purr, SPR_NOACCESS,
+                 &spr_read_purr, SPR_NOACCESS,
+                 0x00000000);
+#endif /* !CONFIG_USER_ONLY */
+    /* Memory management */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_CTRL, "SPR_CTRLT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x80800000);
+    spr_register(env, SPR_UCTRL, "SPR_CTRLF",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x80800000);
+    spr_register(env, SPR_VRSAVE, "SPR_VRSAVE",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    init_excp_POWER7(env);
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+    /* Allocate hardware IRQ controller */
+    ppcPOWER7_irq_init(env);
+    /* Can't find information on what this should be on reset.  This
+     * value is the one used by 74xx processors. */
+    vscr_init(env, 0x00010000);
+}
+#endif /* TARGET_PPC64 */
+
 /* PowerPC 620                                                               */
 #define POWERPC_INSNS_620    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
                               PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
@@ -7031,6 +7136,8 @@ enum {
     CPU_POWERPC_POWER6             = 0x003E0000,
     CPU_POWERPC_POWER6_5           = 0x0F000001, /* POWER6 in POWER5 mode */
     CPU_POWERPC_POWER6A            = 0x0F000002,
+#define CPU_POWERPC_POWER7           CPU_POWERPC_POWER7_v20
+    CPU_POWERPC_POWER7_v20         = 0x003F0200,
     CPU_POWERPC_970                = 0x00390202,
 #define CPU_POWERPC_970FX            CPU_POWERPC_970FX_v31
     CPU_POWERPC_970FX_v10          = 0x00391100,
@@ -8833,6 +8940,9 @@ static const ppc_def_t ppc_defs[] = {
     /* POWER6A                                                               */
     POWERPC_DEF("POWER6A",       CPU_POWERPC_POWER6A,                POWER6),
 #endif
+    /* POWER7                                                                */
+    POWERPC_DEF("POWER7",        CPU_POWERPC_POWER7,                 POWER7),
+    POWERPC_DEF("POWER7_v2.0",   CPU_POWERPC_POWER7_v20,             POWER7),
     /* PowerPC 970                                                           */
     POWERPC_DEF("970",           CPU_POWERPC_970,                    970),
     /* PowerPC 970FX (G5)                                                    */
index e47c372fbd7307b24772e142ac1c35c96901a568..a84b3ee184ba59654bf2b3af6cfe475fd8ad6388 100644 (file)
 #define CPUState struct CPUS390XState
 
 #include "cpu-defs.h"
+#define TARGET_PAGE_BITS 12
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 64
+#define TARGET_VIRT_ADDR_SPACE_BITS 64
+
+#include "cpu-all.h"
 
 #include "softfloat.h"
 
-#define NB_MMU_MODES 2
+#define NB_MMU_MODES 3
 
-typedef union FPReg {
-    struct {
-#ifdef WORDS_BIGENDIAN
-        float32 e;
-        int32_t __pad;
-#else
-        int32_t __pad;
-        float32 e;
-#endif
-    };
-    float64 d;
-    uint64_t i;
-} FPReg;
+#define MMU_MODE0_SUFFIX _primary
+#define MMU_MODE1_SUFFIX _secondary
+#define MMU_MODE2_SUFFIX _home
+
+#define MMU_USER_IDX 1
+
+#define MAX_EXT_QUEUE 16
+
+typedef struct PSW {
+    uint64_t mask;
+    uint64_t addr;
+} PSW;
+
+typedef struct ExtQueue {
+    uint32_t code;
+    uint32_t param;
+    uint32_t param64;
+} ExtQueue;
 
 typedef struct CPUS390XState {
     uint64_t regs[16]; /* GP registers */
@@ -51,17 +62,42 @@ typedef struct CPUS390XState {
     uint32_t aregs[16];        /* access registers */
 
     uint32_t fpc;      /* floating-point control register */
-    FPReg fregs[16]; /* FP registers */
+    CPU_DoubleU fregs[16]; /* FP registers */
     float_status fpu_status; /* passed to softfloat lib */
 
-    struct {
-        uint64_t mask;
-        uint64_t addr;
-    } psw;
+    PSW psw;
 
-    int cc; /* condition code (0-3) */
+    uint32_t cc;
+    uint32_t cc_op;
+    uint64_t cc_src;
+    uint64_t cc_dst;
+    uint64_t cc_vr;
 
     uint64_t __excp_addr;
+    uint64_t psa;
+
+    uint32_t int_pgm_code;
+    uint32_t int_pgm_ilc;
+
+    uint32_t int_svc_code;
+    uint32_t int_svc_ilc;
+
+    uint64_t cregs[16]; /* control registers */
+
+    int pending_int;
+    ExtQueue ext_queue[MAX_EXT_QUEUE];
+
+    /* reset does memset(0) up to here */
+
+    int ext_index;
+    int cpu_num;
+    uint8_t *storage_keys;
+
+    uint64_t tod_offset;
+    uint64_t tod_basetime;
+    QEMUTimer *tod_timer;
+
+    QEMUTimer *cpu_timer;
 
     CPU_COMMON
 } CPUS390XState;
@@ -69,24 +105,174 @@ typedef struct CPUS390XState {
 #if defined(CONFIG_USER_ONLY)
 static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 {
-    if (newsp)
+    if (newsp) {
         env->regs[15] = newsp;
+    }
     env->regs[0] = 0;
 }
 #endif
 
-#define MMU_MODE0_SUFFIX _kernel
-#define MMU_MODE1_SUFFIX _user
-#define MMU_USER_IDX 1
+/* Interrupt Codes */
+/* Program Interrupts */
+#define PGM_OPERATION                   0x0001
+#define PGM_PRIVILEGED                  0x0002
+#define PGM_EXECUTE                     0x0003
+#define PGM_PROTECTION                  0x0004
+#define PGM_ADDRESSING                  0x0005
+#define PGM_SPECIFICATION               0x0006
+#define PGM_DATA                        0x0007
+#define PGM_FIXPT_OVERFLOW              0x0008
+#define PGM_FIXPT_DIVIDE                0x0009
+#define PGM_DEC_OVERFLOW                0x000a
+#define PGM_DEC_DIVIDE                  0x000b
+#define PGM_HFP_EXP_OVERFLOW            0x000c
+#define PGM_HFP_EXP_UNDERFLOW           0x000d
+#define PGM_HFP_SIGNIFICANCE            0x000e
+#define PGM_HFP_DIVIDE                  0x000f
+#define PGM_SEGMENT_TRANS               0x0010
+#define PGM_PAGE_TRANS                  0x0011
+#define PGM_TRANS_SPEC                  0x0012
+#define PGM_SPECIAL_OP                  0x0013
+#define PGM_OPERAND                     0x0015
+#define PGM_TRACE_TABLE                 0x0016
+#define PGM_SPACE_SWITCH                0x001c
+#define PGM_HFP_SQRT                    0x001d
+#define PGM_PC_TRANS_SPEC               0x001f
+#define PGM_AFX_TRANS                   0x0020
+#define PGM_ASX_TRANS                   0x0021
+#define PGM_LX_TRANS                    0x0022
+#define PGM_EX_TRANS                    0x0023
+#define PGM_PRIM_AUTH                   0x0024
+#define PGM_SEC_AUTH                    0x0025
+#define PGM_ALET_SPEC                   0x0028
+#define PGM_ALEN_SPEC                   0x0029
+#define PGM_ALE_SEQ                     0x002a
+#define PGM_ASTE_VALID                  0x002b
+#define PGM_ASTE_SEQ                    0x002c
+#define PGM_EXT_AUTH                    0x002d
+#define PGM_STACK_FULL                  0x0030
+#define PGM_STACK_EMPTY                 0x0031
+#define PGM_STACK_SPEC                  0x0032
+#define PGM_STACK_TYPE                  0x0033
+#define PGM_STACK_OP                    0x0034
+#define PGM_ASCE_TYPE                   0x0038
+#define PGM_REG_FIRST_TRANS             0x0039
+#define PGM_REG_SEC_TRANS               0x003a
+#define PGM_REG_THIRD_TRANS             0x003b
+#define PGM_MONITOR                     0x0040
+#define PGM_PER                         0x0080
+#define PGM_CRYPTO                      0x0119
+
+/* External Interrupts */
+#define EXT_INTERRUPT_KEY               0x0040
+#define EXT_CLOCK_COMP                  0x1004
+#define EXT_CPU_TIMER                   0x1005
+#define EXT_MALFUNCTION                 0x1200
+#define EXT_EMERGENCY                   0x1201
+#define EXT_EXTERNAL_CALL               0x1202
+#define EXT_ETR                         0x1406
+#define EXT_SERVICE                     0x2401
+#define EXT_VIRTIO                      0x2603
+
+/* PSW defines */
+#undef PSW_MASK_PER
+#undef PSW_MASK_DAT
+#undef PSW_MASK_IO
+#undef PSW_MASK_EXT
+#undef PSW_MASK_KEY
+#undef PSW_SHIFT_KEY
+#undef PSW_MASK_MCHECK
+#undef PSW_MASK_WAIT
+#undef PSW_MASK_PSTATE
+#undef PSW_MASK_ASC
+#undef PSW_MASK_CC
+#undef PSW_MASK_PM
+#undef PSW_MASK_64
+
+#define PSW_MASK_PER            0x4000000000000000ULL
+#define PSW_MASK_DAT            0x0400000000000000ULL
+#define PSW_MASK_IO             0x0200000000000000ULL
+#define PSW_MASK_EXT            0x0100000000000000ULL
+#define PSW_MASK_KEY            0x00F0000000000000ULL
+#define PSW_SHIFT_KEY           56
+#define PSW_MASK_MCHECK         0x0004000000000000ULL
+#define PSW_MASK_WAIT           0x0002000000000000ULL
+#define PSW_MASK_PSTATE         0x0001000000000000ULL
+#define PSW_MASK_ASC            0x0000C00000000000ULL
+#define PSW_MASK_CC             0x0000300000000000ULL
+#define PSW_MASK_PM             0x00000F0000000000ULL
+#define PSW_MASK_64             0x0000000100000000ULL
+#define PSW_MASK_32             0x0000000080000000ULL
+
+#undef PSW_ASC_PRIMARY
+#undef PSW_ASC_ACCREG
+#undef PSW_ASC_SECONDARY
+#undef PSW_ASC_HOME
+
+#define PSW_ASC_PRIMARY         0x0000000000000000ULL
+#define PSW_ASC_ACCREG          0x0000400000000000ULL
+#define PSW_ASC_SECONDARY       0x0000800000000000ULL
+#define PSW_ASC_HOME            0x0000C00000000000ULL
+
+/* tb flags */
+
+#define FLAG_MASK_PER           (PSW_MASK_PER    >> 32)
+#define FLAG_MASK_DAT           (PSW_MASK_DAT    >> 32)
+#define FLAG_MASK_IO            (PSW_MASK_IO     >> 32)
+#define FLAG_MASK_EXT           (PSW_MASK_EXT    >> 32)
+#define FLAG_MASK_KEY           (PSW_MASK_KEY    >> 32)
+#define FLAG_MASK_MCHECK        (PSW_MASK_MCHECK >> 32)
+#define FLAG_MASK_WAIT          (PSW_MASK_WAIT   >> 32)
+#define FLAG_MASK_PSTATE        (PSW_MASK_PSTATE >> 32)
+#define FLAG_MASK_ASC           (PSW_MASK_ASC    >> 32)
+#define FLAG_MASK_CC            (PSW_MASK_CC     >> 32)
+#define FLAG_MASK_PM            (PSW_MASK_PM     >> 32)
+#define FLAG_MASK_64            (PSW_MASK_64     >> 32)
+#define FLAG_MASK_32            0x00001000
+
 static inline int cpu_mmu_index (CPUState *env)
 {
-    /* XXX: Currently we don't implement virtual memory */
+    if (env->psw.mask & PSW_MASK_PSTATE) {
+        return 1;
+    }
+
     return 0;
 }
 
+static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->psw.addr;
+    *cs_base = 0;
+    *flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) |
+             ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0);
+}
+
+static inline int get_ilc(uint8_t opc)
+{
+    switch (opc >> 6) {
+    case 0:
+        return 1;
+    case 1:
+    case 2:
+        return 2;
+    case 3:
+        return 3;
+    }
+
+    return 0;
+}
+
+#define ILC_LATER       0x20
+#define ILC_LATER_INC   0x21
+#define ILC_LATER_INC_2 0x22
+
+
 CPUS390XState *cpu_s390x_init(const char *cpu_model);
+void s390x_translate_init(void);
 int cpu_s390x_exec(CPUS390XState *s);
 void cpu_s390x_close(CPUS390XState *s);
+void do_interrupt (CPUState *env);
 
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
@@ -97,41 +283,61 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw
                               int mmu_idx, int is_softmuu);
 #define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
 
-#define TARGET_PAGE_BITS 12
-
-/* ??? This is certainly wrong for 64-bit s390x, but given that only KVM
-   emulation actually works, this is good enough for a placeholder.  */
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
-#define TARGET_VIRT_ADDR_SPACE_BITS 32
 
 #ifndef CONFIG_USER_ONLY
-int s390_virtio_hypercall(CPUState *env);
+int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall);
+
+void kvm_s390_interrupt(CPUState *env, int type, uint32_t code);
 void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token);
+void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
+                                 uint64_t parm64, int vm);
 CPUState *s390_cpu_addr2state(uint16_t cpu_addr);
+
+#ifndef KVM_S390_SIGP_STOP
+#define KVM_S390_SIGP_STOP              0
+#define KVM_S390_PROGRAM_INT            0
+#define KVM_S390_SIGP_SET_PREFIX        0
+#define KVM_S390_RESTART                0
+#define KVM_S390_INT_VIRTIO             0
+#define KVM_S390_INT_SERVICE            0
+#define KVM_S390_INT_EMERGENCY          0
+#endif
+
 #endif
+void cpu_lock(void);
+void cpu_unlock(void);
 
+static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls)
+{
+    env->aregs[0] = newtls >> 32;
+    env->aregs[1] = newtls & 0xffffffffULL;
+}
 
 #define cpu_init cpu_s390x_init
 #define cpu_exec cpu_s390x_exec
 #define cpu_gen_code cpu_s390x_gen_code
+#define cpu_signal_handler cpu_s390x_signal_handler
 
-#include "cpu-all.h"
+#include "exec-all.h"
+
+#ifdef CONFIG_USER_ONLY
 
 #define EXCP_OPEX 1 /* operation exception (sigill) */
 #define EXCP_SVC 2 /* supervisor call (syscall) */
 #define EXCP_ADDR 5 /* addressing exception */
-#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */
+#define EXCP_SPEC 6 /* specification exception */
 
-static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->psw.addr;
-    /* XXX this is correct for user-mode emulation, but needs
-     *     the asce register information as well when softmmu
-     *     is implemented in the future */
-    *cs_base = 0;
-    *flags = env->psw.mask;
-}
+#else
+
+#define EXCP_EXT 1 /* external interrupt */
+#define EXCP_SVC 2 /* supervisor call (syscall) */
+#define EXCP_PGM 3 /* program interruption */
+
+#endif /* CONFIG_USER_ONLY */
+
+#define INTERRUPT_EXT        (1 << 0)
+#define INTERRUPT_TOD        (1 << 1)
+#define INTERRUPT_CPUTIMER   (1 << 2)
 
 /* Program Status Word.  */
 #define S390_PSWM_REGNUM 0
@@ -265,5 +471,485 @@ static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc,
 #define S390_NUM_PSEUDO_REGS 2
 #define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2)
 
+/* CC optimization */
+
+enum cc_op {
+    CC_OP_CONST0 = 0,           /* CC is 0 */
+    CC_OP_CONST1,               /* CC is 1 */
+    CC_OP_CONST2,               /* CC is 2 */
+    CC_OP_CONST3,               /* CC is 3 */
+
+    CC_OP_DYNAMIC,              /* CC calculation defined by env->cc_op */
+    CC_OP_STATIC,               /* CC value is env->cc_op */
+
+    CC_OP_NZ,                   /* env->cc_dst != 0 */
+    CC_OP_LTGT_32,              /* signed less/greater than (32bit) */
+    CC_OP_LTGT_64,              /* signed less/greater than (64bit) */
+    CC_OP_LTUGTU_32,            /* unsigned less/greater than (32bit) */
+    CC_OP_LTUGTU_64,            /* unsigned less/greater than (64bit) */
+    CC_OP_LTGT0_32,             /* signed less/greater than 0 (32bit) */
+    CC_OP_LTGT0_64,             /* signed less/greater than 0 (64bit) */
+
+    CC_OP_ADD_64,               /* overflow on add (64bit) */
+    CC_OP_ADDU_64,              /* overflow on unsigned add (64bit) */
+    CC_OP_SUB_64,               /* overflow on substraction (64bit) */
+    CC_OP_SUBU_64,              /* overflow on unsigned substraction (64bit) */
+    CC_OP_ABS_64,               /* sign eval on abs (64bit) */
+    CC_OP_NABS_64,              /* sign eval on nabs (64bit) */
+
+    CC_OP_ADD_32,               /* overflow on add (32bit) */
+    CC_OP_ADDU_32,              /* overflow on unsigned add (32bit) */
+    CC_OP_SUB_32,               /* overflow on substraction (32bit) */
+    CC_OP_SUBU_32,              /* overflow on unsigned substraction (32bit) */
+    CC_OP_ABS_32,               /* sign eval on abs (64bit) */
+    CC_OP_NABS_32,              /* sign eval on nabs (64bit) */
+
+    CC_OP_COMP_32,              /* complement */
+    CC_OP_COMP_64,              /* complement */
+
+    CC_OP_TM_32,                /* test under mask (32bit) */
+    CC_OP_TM_64,                /* test under mask (64bit) */
+
+    CC_OP_LTGT_F32,             /* FP compare (32bit) */
+    CC_OP_LTGT_F64,             /* FP compare (64bit) */
+
+    CC_OP_NZ_F32,               /* FP dst != 0 (32bit) */
+    CC_OP_NZ_F64,               /* FP dst != 0 (64bit) */
+
+    CC_OP_ICM,                  /* insert characters under mask */
+    CC_OP_SLAG,                 /* Calculate shift left signed */
+    CC_OP_MAX
+};
+
+static const char *cc_names[] = {
+    [CC_OP_CONST0]    = "CC_OP_CONST0",
+    [CC_OP_CONST1]    = "CC_OP_CONST1",
+    [CC_OP_CONST2]    = "CC_OP_CONST2",
+    [CC_OP_CONST3]    = "CC_OP_CONST3",
+    [CC_OP_DYNAMIC]   = "CC_OP_DYNAMIC",
+    [CC_OP_STATIC]    = "CC_OP_STATIC",
+    [CC_OP_NZ]        = "CC_OP_NZ",
+    [CC_OP_LTGT_32]   = "CC_OP_LTGT_32",
+    [CC_OP_LTGT_64]   = "CC_OP_LTGT_64",
+    [CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32",
+    [CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64",
+    [CC_OP_LTGT0_32]  = "CC_OP_LTGT0_32",
+    [CC_OP_LTGT0_64]  = "CC_OP_LTGT0_64",
+    [CC_OP_ADD_64]    = "CC_OP_ADD_64",
+    [CC_OP_ADDU_64]   = "CC_OP_ADDU_64",
+    [CC_OP_SUB_64]    = "CC_OP_SUB_64",
+    [CC_OP_SUBU_64]   = "CC_OP_SUBU_64",
+    [CC_OP_ABS_64]    = "CC_OP_ABS_64",
+    [CC_OP_NABS_64]   = "CC_OP_NABS_64",
+    [CC_OP_ADD_32]    = "CC_OP_ADD_32",
+    [CC_OP_ADDU_32]   = "CC_OP_ADDU_32",
+    [CC_OP_SUB_32]    = "CC_OP_SUB_32",
+    [CC_OP_SUBU_32]   = "CC_OP_SUBU_32",
+    [CC_OP_ABS_32]    = "CC_OP_ABS_32",
+    [CC_OP_NABS_32]   = "CC_OP_NABS_32",
+    [CC_OP_COMP_32]   = "CC_OP_COMP_32",
+    [CC_OP_COMP_64]   = "CC_OP_COMP_64",
+    [CC_OP_TM_32]     = "CC_OP_TM_32",
+    [CC_OP_TM_64]     = "CC_OP_TM_64",
+    [CC_OP_LTGT_F32]  = "CC_OP_LTGT_F32",
+    [CC_OP_LTGT_F64]  = "CC_OP_LTGT_F64",
+    [CC_OP_NZ_F32]    = "CC_OP_NZ_F32",
+    [CC_OP_NZ_F64]    = "CC_OP_NZ_F64",
+    [CC_OP_ICM]       = "CC_OP_ICM",
+    [CC_OP_SLAG]      = "CC_OP_SLAG",
+};
+
+static inline const char *cc_name(int cc_op)
+{
+    return cc_names[cc_op];
+}
+
+/* SCLP PV interface defines */
+#define SCLP_CMDW_READ_SCP_INFO         0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
+
+#define SCP_LENGTH                      0x00
+#define SCP_FUNCTION_CODE               0x02
+#define SCP_CONTROL_MASK                0x03
+#define SCP_RESPONSE_CODE               0x06
+#define SCP_MEM_CODE                    0x08
+#define SCP_INCREMENT                   0x0a
+
+typedef struct LowCore
+{
+    /* prefix area: defined by architecture */
+    uint32_t        ccw1[2];                  /* 0x000 */
+    uint32_t        ccw2[4];                  /* 0x008 */
+    uint8_t         pad1[0x80-0x18];          /* 0x018 */
+    uint32_t        ext_params;               /* 0x080 */
+    uint16_t        cpu_addr;                 /* 0x084 */
+    uint16_t        ext_int_code;             /* 0x086 */
+    uint16_t        svc_ilc;                  /* 0x088 */
+    uint16_t        svc_code;                 /* 0x08a */
+    uint16_t        pgm_ilc;                  /* 0x08c */
+    uint16_t        pgm_code;                 /* 0x08e */
+    uint32_t        data_exc_code;            /* 0x090 */
+    uint16_t        mon_class_num;            /* 0x094 */
+    uint16_t        per_perc_atmid;           /* 0x096 */
+    uint64_t        per_address;              /* 0x098 */
+    uint8_t         exc_access_id;            /* 0x0a0 */
+    uint8_t         per_access_id;            /* 0x0a1 */
+    uint8_t         op_access_id;             /* 0x0a2 */
+    uint8_t         ar_access_id;             /* 0x0a3 */
+    uint8_t         pad2[0xA8-0xA4];          /* 0x0a4 */
+    uint64_t        trans_exc_code;           /* 0x0a8 */
+    uint64_t        monitor_code;             /* 0x0b0 */
+    uint16_t        subchannel_id;            /* 0x0b8 */
+    uint16_t        subchannel_nr;            /* 0x0ba */
+    uint32_t        io_int_parm;              /* 0x0bc */
+    uint32_t        io_int_word;              /* 0x0c0 */
+    uint8_t         pad3[0xc8-0xc4];          /* 0x0c4 */
+    uint32_t        stfl_fac_list;            /* 0x0c8 */
+    uint8_t         pad4[0xe8-0xcc];          /* 0x0cc */
+    uint32_t        mcck_interruption_code[2]; /* 0x0e8 */
+    uint8_t         pad5[0xf4-0xf0];          /* 0x0f0 */
+    uint32_t        external_damage_code;     /* 0x0f4 */
+    uint64_t        failing_storage_address;  /* 0x0f8 */
+    uint8_t         pad6[0x120-0x100];        /* 0x100 */
+    PSW             restart_old_psw;          /* 0x120 */
+    PSW             external_old_psw;         /* 0x130 */
+    PSW             svc_old_psw;              /* 0x140 */
+    PSW             program_old_psw;          /* 0x150 */
+    PSW             mcck_old_psw;             /* 0x160 */
+    PSW             io_old_psw;               /* 0x170 */
+    uint8_t         pad7[0x1a0-0x180];        /* 0x180 */
+    PSW             restart_psw;              /* 0x1a0 */
+    PSW             external_new_psw;         /* 0x1b0 */
+    PSW             svc_new_psw;              /* 0x1c0 */
+    PSW             program_new_psw;          /* 0x1d0 */
+    PSW             mcck_new_psw;             /* 0x1e0 */
+    PSW             io_new_psw;               /* 0x1f0 */
+    PSW             return_psw;               /* 0x200 */
+    uint8_t         irb[64];                  /* 0x210 */
+    uint64_t        sync_enter_timer;         /* 0x250 */
+    uint64_t        async_enter_timer;        /* 0x258 */
+    uint64_t        exit_timer;               /* 0x260 */
+    uint64_t        last_update_timer;        /* 0x268 */
+    uint64_t        user_timer;               /* 0x270 */
+    uint64_t        system_timer;             /* 0x278 */
+    uint64_t        last_update_clock;        /* 0x280 */
+    uint64_t        steal_clock;              /* 0x288 */
+    PSW             return_mcck_psw;          /* 0x290 */
+    uint8_t         pad8[0xc00-0x2a0];        /* 0x2a0 */
+    /* System info area */
+    uint64_t        save_area[16];            /* 0xc00 */
+    uint8_t         pad9[0xd40-0xc80];        /* 0xc80 */
+    uint64_t        kernel_stack;             /* 0xd40 */
+    uint64_t        thread_info;              /* 0xd48 */
+    uint64_t        async_stack;              /* 0xd50 */
+    uint64_t        kernel_asce;              /* 0xd58 */
+    uint64_t        user_asce;                /* 0xd60 */
+    uint64_t        panic_stack;              /* 0xd68 */
+    uint64_t        user_exec_asce;           /* 0xd70 */
+    uint8_t         pad10[0xdc0-0xd78];       /* 0xd78 */
+
+    /* SMP info area: defined by DJB */
+    uint64_t        clock_comparator;         /* 0xdc0 */
+    uint64_t        ext_call_fast;            /* 0xdc8 */
+    uint64_t        percpu_offset;            /* 0xdd0 */
+    uint64_t        current_task;             /* 0xdd8 */
+    uint32_t        softirq_pending;          /* 0xde0 */
+    uint32_t        pad_0x0de4;               /* 0xde4 */
+    uint64_t        int_clock;                /* 0xde8 */
+    uint8_t         pad12[0xe00-0xdf0];       /* 0xdf0 */
+
+    /* 0xe00 is used as indicator for dump tools */
+    /* whether the kernel died with panic() or not */
+    uint32_t        panic_magic;              /* 0xe00 */
+
+    uint8_t         pad13[0x11b8-0xe04];      /* 0xe04 */
+
+    /* 64 bit extparam used for pfault, diag 250 etc  */
+    uint64_t        ext_params2;               /* 0x11B8 */
+
+    uint8_t         pad14[0x1200-0x11C0];      /* 0x11C0 */
+
+    /* System info area */
+
+    uint64_t        floating_pt_save_area[16]; /* 0x1200 */
+    uint64_t        gpregs_save_area[16];      /* 0x1280 */
+    uint32_t        st_status_fixed_logout[4]; /* 0x1300 */
+    uint8_t         pad15[0x1318-0x1310];      /* 0x1310 */
+    uint32_t        prefixreg_save_area;       /* 0x1318 */
+    uint32_t        fpt_creg_save_area;        /* 0x131c */
+    uint8_t         pad16[0x1324-0x1320];      /* 0x1320 */
+    uint32_t        tod_progreg_save_area;     /* 0x1324 */
+    uint32_t        cpu_timer_save_area[2];    /* 0x1328 */
+    uint32_t        clock_comp_save_area[2];   /* 0x1330 */
+    uint8_t         pad17[0x1340-0x1338];      /* 0x1338 */
+    uint32_t        access_regs_save_area[16]; /* 0x1340 */
+    uint64_t        cregs_save_area[16];       /* 0x1380 */
+
+    /* align to the top of the prefix area */
+
+    uint8_t         pad18[0x2000-0x1400];      /* 0x1400 */
+} __attribute__((packed)) LowCore;
+
+/* STSI */
+#define STSI_LEVEL_MASK         0x00000000f0000000ULL
+#define STSI_LEVEL_CURRENT      0x0000000000000000ULL
+#define STSI_LEVEL_1            0x0000000010000000ULL
+#define STSI_LEVEL_2            0x0000000020000000ULL
+#define STSI_LEVEL_3            0x0000000030000000ULL
+#define STSI_R0_RESERVED_MASK   0x000000000fffff00ULL
+#define STSI_R0_SEL1_MASK       0x00000000000000ffULL
+#define STSI_R1_RESERVED_MASK   0x00000000ffff0000ULL
+#define STSI_R1_SEL2_MASK       0x000000000000ffffULL
+
+/* Basic Machine Configuration */
+struct sysib_111 {
+    uint32_t res1[8];
+    uint8_t  manuf[16];
+    uint8_t  type[4];
+    uint8_t  res2[12];
+    uint8_t  model[16];
+    uint8_t  sequence[16];
+    uint8_t  plant[4];
+    uint8_t  res3[156];
+};
+
+/* Basic Machine CPU */
+struct sysib_121 {
+    uint32_t res1[80];
+    uint8_t  sequence[16];
+    uint8_t  plant[4];
+    uint8_t  res2[2];
+    uint16_t cpu_addr;
+    uint8_t  res3[152];
+};
+
+/* Basic Machine CPUs */
+struct sysib_122 {
+    uint8_t res1[32];
+    uint32_t capability;
+    uint16_t total_cpus;
+    uint16_t active_cpus;
+    uint16_t standby_cpus;
+    uint16_t reserved_cpus;
+    uint16_t adjustments[2026];
+};
+
+/* LPAR CPU */
+struct sysib_221 {
+    uint32_t res1[80];
+    uint8_t  sequence[16];
+    uint8_t  plant[4];
+    uint16_t cpu_id;
+    uint16_t cpu_addr;
+    uint8_t  res3[152];
+};
+
+/* LPAR CPUs */
+struct sysib_222 {
+    uint32_t res1[32];
+    uint16_t lpar_num;
+    uint8_t  res2;
+    uint8_t  lcpuc;
+    uint16_t total_cpus;
+    uint16_t conf_cpus;
+    uint16_t standby_cpus;
+    uint16_t reserved_cpus;
+    uint8_t  name[8];
+    uint32_t caf;
+    uint8_t  res3[16];
+    uint16_t dedicated_cpus;
+    uint16_t shared_cpus;
+    uint8_t  res4[180];
+};
+
+/* VM CPUs */
+struct sysib_322 {
+    uint8_t  res1[31];
+    uint8_t  count;
+    struct {
+        uint8_t  res2[4];
+        uint16_t total_cpus;
+        uint16_t conf_cpus;
+        uint16_t standby_cpus;
+        uint16_t reserved_cpus;
+        uint8_t  name[8];
+        uint32_t caf;
+        uint8_t  cpi[16];
+        uint8_t  res3[24];
+    } vm[8];
+    uint8_t res4[3552];
+};
+
+/* MMU defines */
+#define _ASCE_ORIGIN            ~0xfffULL /* segment table origin             */
+#define _ASCE_SUBSPACE          0x200     /* subspace group control           */
+#define _ASCE_PRIVATE_SPACE     0x100     /* private space control            */
+#define _ASCE_ALT_EVENT         0x80      /* storage alteration event control */
+#define _ASCE_SPACE_SWITCH      0x40      /* space switch event               */
+#define _ASCE_REAL_SPACE        0x20      /* real space control               */
+#define _ASCE_TYPE_MASK         0x0c      /* asce table type mask             */
+#define _ASCE_TYPE_REGION1      0x0c      /* region first table type          */
+#define _ASCE_TYPE_REGION2      0x08      /* region second table type         */
+#define _ASCE_TYPE_REGION3      0x04      /* region third table type          */
+#define _ASCE_TYPE_SEGMENT      0x00      /* segment table type               */
+#define _ASCE_TABLE_LENGTH      0x03      /* region table length              */
+
+#define _REGION_ENTRY_ORIGIN    ~0xfffULL /* region/segment table origin      */
+#define _REGION_ENTRY_INV       0x20      /* invalid region table entry       */
+#define _REGION_ENTRY_TYPE_MASK 0x0c      /* region/segment table type mask   */
+#define _REGION_ENTRY_TYPE_R1   0x0c      /* region first table type          */
+#define _REGION_ENTRY_TYPE_R2   0x08      /* region second table type         */
+#define _REGION_ENTRY_TYPE_R3   0x04      /* region third table type          */
+#define _REGION_ENTRY_LENGTH    0x03      /* region third length              */
+
+#define _SEGMENT_ENTRY_ORIGIN   ~0x7ffULL /* segment table origin             */
+#define _SEGMENT_ENTRY_RO       0x200     /* page protection bit              */
+#define _SEGMENT_ENTRY_INV      0x20      /* invalid segment table entry      */
+
+#define _PAGE_RO        0x200            /* HW read-only bit  */
+#define _PAGE_INVALID   0x400            /* HW invalid bit    */
+
+
+
+/* EBCDIC handling */
+static const uint8_t ebcdic2ascii[] = {
+    0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+    0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+    0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+    0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+    0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+    0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+    0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+    0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
+    0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+    0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
+    0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+    0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+    0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+    0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+    0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+    0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+    0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+    0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+    0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+    0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
+    0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+    0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+    0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+    0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+    0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+    0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
+};
+
+static const uint8_t ascii2ebcdic [] = {
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+    0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+    0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+    0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+    0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+    0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+    0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+    0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+    0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+    0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+    0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+    0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+    0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++) {
+        p[i] = ascii2ebcdic[(int)ascii[i]];
+    }
+}
+
+#define SIGP_SENSE             0x01
+#define SIGP_EXTERNAL_CALL     0x02
+#define SIGP_EMERGENCY         0x03
+#define SIGP_START             0x04
+#define SIGP_STOP              0x05
+#define SIGP_RESTART           0x06
+#define SIGP_STOP_STORE_STATUS 0x09
+#define SIGP_INITIAL_CPU_RESET 0x0b
+#define SIGP_CPU_RESET         0x0c
+#define SIGP_SET_PREFIX        0x0d
+#define SIGP_STORE_STATUS_ADDR 0x0e
+#define SIGP_SET_ARCH          0x12
+
+/* cpu status bits */
+#define SIGP_STAT_EQUIPMENT_CHECK   0x80000000UL
+#define SIGP_STAT_INCORRECT_STATE   0x00000200UL
+#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
+#define SIGP_STAT_EXT_CALL_PENDING  0x00000080UL
+#define SIGP_STAT_STOPPED           0x00000040UL
+#define SIGP_STAT_OPERATOR_INTERV   0x00000020UL
+#define SIGP_STAT_CHECK_STOP        0x00000010UL
+#define SIGP_STAT_INOPERATIVE       0x00000004UL
+#define SIGP_STAT_INVALID_ORDER     0x00000002UL
+#define SIGP_STAT_RECEIVER_CHECK    0x00000001UL
+
+void load_psw(CPUState *env, uint64_t mask, uint64_t addr);
+int mmu_translate(CPUState *env, target_ulong vaddr, int rw, uint64_t asc,
+                  target_ulong *raddr, int *flags);
+int sclp_service_call(CPUState *env, uint32_t sccb, uint64_t code);
+uint32_t calc_cc(CPUState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
+                 uint64_t vr);
+
+#define TARGET_HAS_ICE 1
+
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
+/* Converts ns to s390's clock format */
+static inline uint64_t time2tod(uint64_t ns) {
+    return (ns << 9) / 125;
+}
+
+static inline void cpu_inject_ext(CPUState *env, uint32_t code, uint32_t param,
+                                  uint64_t param64)
+{
+    if (env->ext_index == MAX_EXT_QUEUE - 1) {
+        /* ugh - can't queue anymore. Let's drop. */
+        return;
+    }
+
+    env->ext_index++;
+    assert(env->ext_index < MAX_EXT_QUEUE);
+
+    env->ext_queue[env->ext_index].code = code;
+    env->ext_queue[env->ext_index].param = param;
+    env->ext_queue[env->ext_index].param64 = param64;
+
+    env->pending_int |= INTERRUPT_EXT;
+    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+}
 
 #endif
index f7893f3877886f915e793488f40b814bd27b6e94..7a87fffca6ddb0dcc8b10095dcf9875e9768d5e6 100644 (file)
@@ -31,7 +31,16 @@ register struct CPUS390XState *env asm(AREG0);
 
 static inline int cpu_has_work(CPUState *env)
 {
-    return env->interrupt_request & CPU_INTERRUPT_HARD; // guess
+    return ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+            (env->psw.mask & PSW_MASK_EXT));
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+static inline void env_to_regs(void)
+{
 }
 
 static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb)
index 4a5297be181ef9bf193327f2088844112edb0e6a..629dfd97087d48d12a6cb9e0928e997a3eea2b67 100644 (file)
@@ -82,3 +82,7 @@ int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
     return 0;
 }
 #endif /* CONFIG_USER_ONLY */
+
+void do_interrupt (CPUState *env)
+{
+}
index 91232038ea7334eac9e5086369e01d92b26b477b..26434607221143c5dfbef073c2a0abcb53387cd6 100644 (file)
@@ -182,8 +182,8 @@ int kvm_arch_process_async_events(CPUState *env)
     return 0;
 }
 
-static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
-                                        uint64_t parm64, int vm)
+void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
+                                 uint64_t parm64, int vm)
 {
     struct kvm_s390_interrupt kvmint;
     int r;
@@ -218,7 +218,7 @@ void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token)
                                 token, 1);
 }
 
-static void kvm_s390_interrupt(CPUState *env, int type, uint32_t code)
+void kvm_s390_interrupt(CPUState *env, int type, uint32_t code)
 {
     kvm_s390_interrupt_internal(env, type, code, 0, 0);
 }
@@ -237,7 +237,8 @@ static void setcc(CPUState *env, uint64_t cc)
     env->psw.mask |= (cc & 3) << 44;
 }
 
-static int sclp_service_call(CPUState *env, struct kvm_run *run, uint16_t ipbh0)
+static int kvm_sclp_service_call(CPUState *env, struct kvm_run *run,
+                                 uint16_t ipbh0)
 {
     uint32_t sccb;
     uint64_t code;
@@ -287,7 +288,7 @@ static int handle_priv(CPUState *env, struct kvm_run *run, uint8_t ipa1)
     dprintf("KVM: PRIV: %d\n", ipa1);
     switch (ipa1) {
         case PRIV_SCLP_CALL:
-            r = sclp_service_call(env, run, ipbh0);
+            r = kvm_sclp_service_call(env, run, ipbh0);
             break;
         default:
             dprintf("KVM: unknown PRIV: 0x%x\n", ipa1);
@@ -300,12 +301,10 @@ static int handle_priv(CPUState *env, struct kvm_run *run, uint8_t ipa1)
 
 static int handle_hypercall(CPUState *env, struct kvm_run *run)
 {
-    int r;
-
     cpu_synchronize_state(env);
-    r = s390_virtio_hypercall(env);
+    env->regs[2] = s390_virtio_hypercall(env, env->regs[2], env->regs[1]);
 
-    return r;
+    return 0;
 }
 
 static int handle_diag(CPUState *env, struct kvm_run *run, int ipb_code)
@@ -441,7 +440,7 @@ static int handle_instruction(CPUState *env, struct kvm_run *run)
     if (r < 0) {
         enter_pgmcheck(env, 0x0001);
     }
-    return r;
+    return 0;
 }
 
 static int handle_intercept(CPUState *env)
index 402df2d85e50819e71c754d361d68e5b1e00b56f..be455b9de23cff49b2af4d42c144cefcc9e27956 100644 (file)
@@ -61,7 +61,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *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, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         /* XXX */
index d33bfb1f310f60517f86f899f1f665c4a1942e98..4d45e32616168770755fa1271ced6fa3382e45fa 100644 (file)
@@ -36,7 +36,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
         }
     }
     for (i = 0; i < 16; i++) {
-        cpu_fprintf(f, "F%02d=%016lx", i, (long)env->fregs[i].i);
+        cpu_fprintf(f, "F%02d=%016" PRIx64, i, *(uint64_t *)&env->fregs[i]);
         if ((i % 4) == 3) {
             cpu_fprintf(f, "\n");
         } else {
@@ -54,8 +54,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
 {
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->psw.addr = gen_opc_pc[pc_pos];
 }
index 2e527684142795f1bd06e98db13dd7bea5776d54..95e3c7c8f77da538b18822ff04e2b5f80518e3e5 100644 (file)
@@ -23,31 +23,31 @@ DEF_HELPER_2(macw, void, i32, i32)
 
 DEF_HELPER_1(ld_fpscr, void, i32)
 
-DEF_HELPER_1(fabs_FT, i32, i32)
-DEF_HELPER_1(fabs_DT, i64, i64)
-DEF_HELPER_2(fadd_FT, i32, i32, i32)
-DEF_HELPER_2(fadd_DT, i64, i64, i64)
-DEF_HELPER_1(fcnvsd_FT_DT, i64, i32)
-DEF_HELPER_1(fcnvds_DT_FT, i32, i64)
+DEF_HELPER_1(fabs_FT, f32, f32)
+DEF_HELPER_1(fabs_DT, f64, f64)
+DEF_HELPER_2(fadd_FT, f32, f32, f32)
+DEF_HELPER_2(fadd_DT, f64, f64, f64)
+DEF_HELPER_1(fcnvsd_FT_DT, f64, f32)
+DEF_HELPER_1(fcnvds_DT_FT, f32, f64)
 
-DEF_HELPER_2(fcmp_eq_FT, void, i32, i32)
-DEF_HELPER_2(fcmp_eq_DT, void, i64, i64)
-DEF_HELPER_2(fcmp_gt_FT, void, i32, i32)
-DEF_HELPER_2(fcmp_gt_DT, void, i64, i64)
-DEF_HELPER_2(fdiv_FT, i32, i32, i32)
-DEF_HELPER_2(fdiv_DT, i64, i64, i64)
-DEF_HELPER_1(float_FT, i32, i32)
-DEF_HELPER_1(float_DT, i64, i32)
-DEF_HELPER_3(fmac_FT, i32, i32, i32, i32)
-DEF_HELPER_2(fmul_FT, i32, i32, i32)
-DEF_HELPER_2(fmul_DT, i64, i64, i64)
-DEF_HELPER_1(fneg_T, i32, i32)
-DEF_HELPER_2(fsub_FT, i32, i32, i32)
-DEF_HELPER_2(fsub_DT, i64, i64, i64)
-DEF_HELPER_1(fsqrt_FT, i32, i32)
-DEF_HELPER_1(fsqrt_DT, i64, i64)
-DEF_HELPER_1(ftrc_FT, i32, i32)
-DEF_HELPER_1(ftrc_DT, i32, i64)
+DEF_HELPER_2(fcmp_eq_FT, void, f32, f32)
+DEF_HELPER_2(fcmp_eq_DT, void, f64, f64)
+DEF_HELPER_2(fcmp_gt_FT, void, f32, f32)
+DEF_HELPER_2(fcmp_gt_DT, void, f64, f64)
+DEF_HELPER_2(fdiv_FT, f32, f32, f32)
+DEF_HELPER_2(fdiv_DT, f64, f64, f64)
+DEF_HELPER_1(float_FT, f32, i32)
+DEF_HELPER_1(float_DT, f64, i32)
+DEF_HELPER_3(fmac_FT, f32, f32, f32, f32)
+DEF_HELPER_2(fmul_FT, f32, f32, f32)
+DEF_HELPER_2(fmul_DT, f64, f64, f64)
+DEF_HELPER_1(fneg_T, f32, f32)
+DEF_HELPER_2(fsub_FT, f32, f32, f32)
+DEF_HELPER_2(fsub_DT, f64, f64, f64)
+DEF_HELPER_1(fsqrt_FT, f32, f32)
+DEF_HELPER_1(fsqrt_DT, f64, f64)
+DEF_HELPER_1(ftrc_FT, i32, f32)
+DEF_HELPER_1(ftrc_DT, i32, f64)
 DEF_HELPER_2(fipr, void, i32, i32)
 DEF_HELPER_1(ftrv, void, i32)
 
index b8f4ca28eda082346633e33f29818b20a5061744..b909d18bc451b9ab8570c0475151cb28a07a7f30 100644 (file)
@@ -32,7 +32,7 @@ static void cpu_restore_state_from_retaddr(void *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, NULL);
+            cpu_restore_state(tb, env, pc);
         }
     }
 }
@@ -487,53 +487,38 @@ static void update_fpscr(void *retaddr)
     }
 }
 
-uint32_t helper_fabs_FT(uint32_t t0)
+float32 helper_fabs_FT(float32 t0)
 {
-    CPU_FloatU f;
-    f.l = t0;
-    f.f = float32_abs(f.f);
-    return f.l;
+    return float32_abs(t0);
 }
 
-uint64_t helper_fabs_DT(uint64_t t0)
+float64 helper_fabs_DT(float64 t0)
 {
-    CPU_DoubleU d;
-    d.ll = t0;
-    d.d = float64_abs(d.d);
-    return d.ll;
+    return float64_abs(t0);
 }
 
-uint32_t helper_fadd_FT(uint32_t t0, uint32_t t1)
+float32 helper_fadd_FT(float32 t0, float32 t1)
 {
-    CPU_FloatU f0, f1;
-    f0.l = t0;
-    f1.l = t1;
     set_float_exception_flags(0, &env->fp_status);
-    f0.f = float32_add(f0.f, f1.f, &env->fp_status);
+    t0 = float32_add(t0, t1, &env->fp_status);
     update_fpscr(GETPC());
-    return f0.l;
+    return t0;
 }
 
-uint64_t helper_fadd_DT(uint64_t t0, uint64_t t1)
+float64 helper_fadd_DT(float64 t0, float64 t1)
 {
-    CPU_DoubleU d0, d1;
-    d0.ll = t0;
-    d1.ll = t1;
     set_float_exception_flags(0, &env->fp_status);
-    d0.d = float64_add(d0.d, d1.d, &env->fp_status);
+    t0 = float64_add(t0, t1, &env->fp_status);
     update_fpscr(GETPC());
-    return d0.ll;
+    return t0;
 }
 
-void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1)
+void helper_fcmp_eq_FT(float32 t0, float32 t1)
 {
-    CPU_FloatU f0, f1;
     int relation;
-    f0.l = t0;
-    f1.l = t1;
 
     set_float_exception_flags(0, &env->fp_status);
-    relation = float32_compare(f0.f, f1.f, &env->fp_status);
+    relation = float32_compare(t0, t1, &env->fp_status);
     if (unlikely(relation == float_relation_unordered)) {
         update_fpscr(GETPC());
     } else if (relation == float_relation_equal) {
@@ -543,15 +528,12 @@ void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1)
     }
 }
 
-void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1)
+void helper_fcmp_eq_DT(float64 t0, float64 t1)
 {
-    CPU_DoubleU d0, d1;
     int relation;
-    d0.ll = t0;
-    d1.ll = t1;
 
     set_float_exception_flags(0, &env->fp_status);
-    relation = float64_compare(d0.d, d1.d, &env->fp_status);
+    relation = float64_compare(t0, t1, &env->fp_status);
     if (unlikely(relation == float_relation_unordered)) {
         update_fpscr(GETPC());
     } else if (relation == float_relation_equal) {
@@ -561,15 +543,12 @@ void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1)
     }
 }
 
-void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1)
+void helper_fcmp_gt_FT(float32 t0, float32 t1)
 {
-    CPU_FloatU f0, f1;
     int relation;
-    f0.l = t0;
-    f1.l = t1;
 
     set_float_exception_flags(0, &env->fp_status);
-    relation = float32_compare(f0.f, f1.f, &env->fp_status);
+    relation = float32_compare(t0, t1, &env->fp_status);
     if (unlikely(relation == float_relation_unordered)) {
         update_fpscr(GETPC());
     } else if (relation == float_relation_greater) {
@@ -579,15 +558,12 @@ void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1)
     }
 }
 
-void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1)
+void helper_fcmp_gt_DT(float64 t0, float64 t1)
 {
-    CPU_DoubleU d0, d1;
     int relation;
-    d0.ll = t0;
-    d1.ll = t1;
 
     set_float_exception_flags(0, &env->fp_status);
-    relation = float64_compare(d0.d, d1.d, &env->fp_status);
+    relation = float64_compare(t0, t1, &env->fp_status);
     if (unlikely(relation == float_relation_unordered)) {
         update_fpscr(GETPC());
     } else if (relation == float_relation_greater) {
@@ -597,176 +573,134 @@ void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1)
     }
 }
 
-uint64_t helper_fcnvsd_FT_DT(uint32_t t0)
+float64 helper_fcnvsd_FT_DT(float32 t0)
 {
-    CPU_DoubleU d;
-    CPU_FloatU f;
-    f.l = t0;
+    float64 ret;
     set_float_exception_flags(0, &env->fp_status);
-    d.d = float32_to_float64(f.f, &env->fp_status);
+    ret = float32_to_float64(t0, &env->fp_status);
     update_fpscr(GETPC());
-    return d.ll;
+    return ret;
 }
 
-uint32_t helper_fcnvds_DT_FT(uint64_t t0)
+float32 helper_fcnvds_DT_FT(float64 t0)
 {
-    CPU_DoubleU d;
-    CPU_FloatU f;
-    d.ll = t0;
+    float32 ret;
     set_float_exception_flags(0, &env->fp_status);
-    f.f = float64_to_float32(d.d, &env->fp_status);
+    ret = float64_to_float32(t0, &env->fp_status);
     update_fpscr(GETPC());
-    return f.l;
+    return ret;
 }
 
-uint32_t helper_fdiv_FT(uint32_t t0, uint32_t t1)
+float32 helper_fdiv_FT(float32 t0, float32 t1)
 {
-    CPU_FloatU f0, f1;
-    f0.l = t0;
-    f1.l = t1;
     set_float_exception_flags(0, &env->fp_status);
-    f0.f = float32_div(f0.f, f1.f, &env->fp_status);
+    t0 = float32_div(t0, t1, &env->fp_status);
     update_fpscr(GETPC());
-    return f0.l;
+    return t0;
 }
 
-uint64_t helper_fdiv_DT(uint64_t t0, uint64_t t1)
+float64 helper_fdiv_DT(float64 t0, float64 t1)
 {
-    CPU_DoubleU d0, d1;
-    d0.ll = t0;
-    d1.ll = t1;
     set_float_exception_flags(0, &env->fp_status);
-    d0.d = float64_div(d0.d, d1.d, &env->fp_status);
+    t0 = float64_div(t0, t1, &env->fp_status);
     update_fpscr(GETPC());
-    return d0.ll;
+    return t0;
 }
 
-uint32_t helper_float_FT(uint32_t t0)
+float32 helper_float_FT(uint32_t t0)
 {
-    CPU_FloatU f;
-
+    float32 ret;
     set_float_exception_flags(0, &env->fp_status);
-    f.f = int32_to_float32(t0, &env->fp_status);
+    ret = int32_to_float32(t0, &env->fp_status);
     update_fpscr(GETPC());
-
-    return f.l;
+    return ret;
 }
 
-uint64_t helper_float_DT(uint32_t t0)
+float64 helper_float_DT(uint32_t t0)
 {
-    CPU_DoubleU d;
+    float64 ret;
     set_float_exception_flags(0, &env->fp_status);
-    d.d = int32_to_float64(t0, &env->fp_status);
+    ret = int32_to_float64(t0, &env->fp_status);
     update_fpscr(GETPC());
-    return d.ll;
+    return ret;
 }
 
-uint32_t helper_fmac_FT(uint32_t t0, uint32_t t1, uint32_t t2)
+float32 helper_fmac_FT(float32 t0, float32 t1, float32 t2)
 {
-    CPU_FloatU f0, f1, f2;
-    f0.l = t0;
-    f1.l = t1;
-    f2.l = t2;
     set_float_exception_flags(0, &env->fp_status);
-    f0.f = float32_mul(f0.f, f1.f, &env->fp_status);
-    f0.f = float32_add(f0.f, f2.f, &env->fp_status);
+    t0 = float32_mul(t0, t1, &env->fp_status);
+    t0 = float32_add(t0, t2, &env->fp_status);
     update_fpscr(GETPC());
-
-    return f0.l;
+    return t0;
 }
 
-uint32_t helper_fmul_FT(uint32_t t0, uint32_t t1)
+float32 helper_fmul_FT(float32 t0, float32 t1)
 {
-    CPU_FloatU f0, f1;
-    f0.l = t0;
-    f1.l = t1;
     set_float_exception_flags(0, &env->fp_status);
-    f0.f = float32_mul(f0.f, f1.f, &env->fp_status);
+    t0 = float32_mul(t0, t1, &env->fp_status);
     update_fpscr(GETPC());
-    return f0.l;
+    return t0;
 }
 
-uint64_t helper_fmul_DT(uint64_t t0, uint64_t t1)
+float64 helper_fmul_DT(float64 t0, float64 t1)
 {
-    CPU_DoubleU d0, d1;
-    d0.ll = t0;
-    d1.ll = t1;
     set_float_exception_flags(0, &env->fp_status);
-    d0.d = float64_mul(d0.d, d1.d, &env->fp_status);
+    t0 = float64_mul(t0, t1, &env->fp_status);
     update_fpscr(GETPC());
-
-    return d0.ll;
+    return t0;
 }
 
-uint32_t helper_fneg_T(uint32_t t0)
+float32 helper_fneg_T(float32 t0)
 {
-    CPU_FloatU f;
-    f.l = t0;
-    f.f = float32_chs(f.f);
-    return f.l;
+    return float32_chs(t0);
 }
 
-uint32_t helper_fsqrt_FT(uint32_t t0)
+float32 helper_fsqrt_FT(float32 t0)
 {
-    CPU_FloatU f;
-    f.l = t0;
     set_float_exception_flags(0, &env->fp_status);
-    f.f = float32_sqrt(f.f, &env->fp_status);
+    t0 = float32_sqrt(t0, &env->fp_status);
     update_fpscr(GETPC());
-    return f.l;
+    return t0;
 }
 
-uint64_t helper_fsqrt_DT(uint64_t t0)
+float64 helper_fsqrt_DT(float64 t0)
 {
-    CPU_DoubleU d;
-    d.ll = t0;
     set_float_exception_flags(0, &env->fp_status);
-    d.d = float64_sqrt(d.d, &env->fp_status);
+    t0 = float64_sqrt(t0, &env->fp_status);
     update_fpscr(GETPC());
-    return d.ll;
+    return t0;
 }
 
-uint32_t helper_fsub_FT(uint32_t t0, uint32_t t1)
+float32 helper_fsub_FT(float32 t0, float32 t1)
 {
-    CPU_FloatU f0, f1;
-    f0.l = t0;
-    f1.l = t1;
     set_float_exception_flags(0, &env->fp_status);
-    f0.f = float32_sub(f0.f, f1.f, &env->fp_status);
+    t0 = float32_sub(t0, t1, &env->fp_status);
     update_fpscr(GETPC());
-    return f0.l;
+    return t0;
 }
 
-uint64_t helper_fsub_DT(uint64_t t0, uint64_t t1)
+float64 helper_fsub_DT(float64 t0, float64 t1)
 {
-    CPU_DoubleU d0, d1;
-
-    d0.ll = t0;
-    d1.ll = t1;
     set_float_exception_flags(0, &env->fp_status);
-    d0.d = float64_sub(d0.d, d1.d, &env->fp_status);
+    t0 = float64_sub(t0, t1, &env->fp_status);
     update_fpscr(GETPC());
-    return d0.ll;
+    return t0;
 }
 
-uint32_t helper_ftrc_FT(uint32_t t0)
+uint32_t helper_ftrc_FT(float32 t0)
 {
-    CPU_FloatU f;
     uint32_t ret;
-    f.l = t0;
     set_float_exception_flags(0, &env->fp_status);
-    ret = float32_to_int32_round_to_zero(f.f, &env->fp_status);
+    ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
     update_fpscr(GETPC());
     return ret;
 }
 
-uint32_t helper_ftrc_DT(uint64_t t0)
+uint32_t helper_ftrc_DT(float64 t0)
 {
-    CPU_DoubleU d;
     uint32_t ret;
-    d.ll = t0;
     set_float_exception_flags(0, &env->fp_status);
-    ret = float64_to_int32_round_to_zero(d.d, &env->fp_status);
+    ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
     update_fpscr(GETPC());
     return ret;
 }
index 58e9b8f93b39f58003da9607d3aee337c37d0cda..93c863650d96fac225e2f7cb030d43a11adef183 100644 (file)
@@ -302,7 +302,7 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
        /* Use a direct jump if in same page and singlestep not enabled */
         tcg_gen_goto_tb(n);
         tcg_gen_movi_i32(cpu_pc, dest);
-        tcg_gen_exit_tb((long) tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         tcg_gen_movi_i32(cpu_pc, dest);
         if (ctx->singlestep_enabled)
@@ -2069,8 +2069,7 @@ void gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->pc = gen_opc_pc[pc_pos];
     env->flags = gen_opc_hflags[pc_pos];
index 854f168c60c7a0381960f90f30166f954825c0d1..ffffb8c0bd544ab479a7a32a208d9de13aff62d9 100644 (file)
@@ -4375,7 +4375,7 @@ static void cpu_restore_state2(void *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, (void *)(long)env->cond);
+            cpu_restore_state(tb, env, pc);
         }
     }
 }
index e26462eef5895306b08f7e5d9b300d1817896fd1..3c958b26d6d9dda7502191694f2566320b038ce3 100644 (file)
@@ -241,7 +241,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num,
         tcg_gen_goto_tb(tb_num);
         tcg_gen_movi_tl(cpu_pc, pc);
         tcg_gen_movi_tl(cpu_npc, npc);
-        tcg_gen_exit_tb((long)tb + tb_num);
+        tcg_gen_exit_tb((tcg_target_long)tb + tb_num);
     } else {
         /* jump to another page: currently not optimized */
         tcg_gen_movi_tl(cpu_pc, pc);
@@ -5080,8 +5080,7 @@ void gen_intermediate_code_init(CPUSPARCState *env)
     }
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     target_ulong npc;
     env->pc = gen_opc_pc[pc_pos];
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
new file mode 100644 (file)
index 0000000..1e10049
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * UniCore32 virtual CPU header
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#ifndef __CPU_UC32_H__
+#define __CPU_UC32_H__
+
+#define TARGET_LONG_BITS                32
+#define TARGET_PAGE_BITS                12
+
+#define TARGET_PHYS_ADDR_SPACE_BITS     32
+#define TARGET_VIRT_ADDR_SPACE_BITS     32
+
+#define ELF_MACHINE             EM_UNICORE32
+
+#define CPUState                struct CPUState_UniCore32
+
+#include "cpu-defs.h"
+#include "softfloat.h"
+
+#define NB_MMU_MODES            2
+
+typedef struct CPUState_UniCore32 {
+    /* Regs for current mode.  */
+    uint32_t regs[32];
+    /* Frequently accessed ASR bits are stored separately for efficiently.
+       This contains all the other bits.  Use asr_{read,write} to access
+       the whole ASR.  */
+    uint32_t uncached_asr;
+    uint32_t bsr;
+
+    /* Banked registers.  */
+    uint32_t banked_bsr[6];
+    uint32_t banked_r29[6];
+    uint32_t banked_r30[6];
+
+    /* asr flag cache for faster execution */
+    uint32_t CF; /* 0 or 1 */
+    uint32_t VF; /* V is the bit 31. All other bits are undefined */
+    uint32_t NF; /* N is bit 31. All other bits are undefined.  */
+    uint32_t ZF; /* Z set if zero.  */
+
+    /* System control coprocessor (cp0) */
+    struct {
+        uint32_t c0_cpuid;
+        uint32_t c0_cachetype;
+        uint32_t c1_sys; /* System control register.  */
+        uint32_t c2_base; /* MMU translation table base.  */
+        uint32_t c3_faultstatus; /* Fault status registers.  */
+        uint32_t c4_faultaddr; /* Fault address registers.  */
+        uint32_t c5_cacheop; /* Cache operation registers.  */
+        uint32_t c6_tlbop; /* TLB operation registers. */
+    } cp0;
+
+    /* UniCore-F64 coprocessor state.  */
+    struct {
+        float64 regs[16];
+        uint32_t xregs[32];
+        float_status fp_status;
+    } ucf64;
+
+    CPU_COMMON
+
+    /* Internal CPU feature flags.  */
+    uint32_t features;
+
+} CPUState_UniCore32;
+
+#define ASR_M                   (0x1f)
+#define ASR_MODE_USER           (0x10)
+#define ASR_MODE_INTR           (0x12)
+#define ASR_MODE_PRIV           (0x13)
+#define ASR_MODE_TRAP           (0x17)
+#define ASR_MODE_EXTN           (0x1b)
+#define ASR_MODE_SUSR           (0x1f)
+#define ASR_I                   (1 << 7)
+#define ASR_V                   (1 << 28)
+#define ASR_C                   (1 << 29)
+#define ASR_Z                   (1 << 30)
+#define ASR_N                   (1 << 31)
+#define ASR_NZCV                (ASR_N | ASR_Z | ASR_C | ASR_V)
+#define ASR_RESERVED            (~(ASR_M | ASR_I | ASR_NZCV))
+
+#define UC32_EXCP_PRIV          (ASR_MODE_PRIV)
+#define UC32_EXCP_TRAP          (ASR_MODE_TRAP)
+
+/* Return the current ASR value.  */
+target_ulong cpu_asr_read(CPUState *env1);
+/* Set the ASR.  Note that some bits of mask must be all-set or all-clear.  */
+void cpu_asr_write(CPUState *env1, target_ulong val, target_ulong mask);
+
+/* UniCore-F64 system registers.  */
+#define UC32_UCF64_FPSCR                (31)
+#define UCF64_FPSCR_MASK                (0x27ffffff)
+#define UCF64_FPSCR_RND_MASK            (0x7)
+#define UCF64_FPSCR_RND(r)              (((r) >>  0) & UCF64_FPSCR_RND_MASK)
+#define UCF64_FPSCR_TRAPEN_MASK         (0x7f)
+#define UCF64_FPSCR_TRAPEN(r)           (((r) >> 10) & UCF64_FPSCR_TRAPEN_MASK)
+#define UCF64_FPSCR_FLAG_MASK           (0x3ff)
+#define UCF64_FPSCR_FLAG(r)             (((r) >> 17) & UCF64_FPSCR_FLAG_MASK)
+#define UCF64_FPSCR_FLAG_ZERO           (1 << 17)
+#define UCF64_FPSCR_FLAG_INFINITY       (1 << 18)
+#define UCF64_FPSCR_FLAG_INVALID        (1 << 19)
+#define UCF64_FPSCR_FLAG_UNDERFLOW      (1 << 20)
+#define UCF64_FPSCR_FLAG_OVERFLOW       (1 << 21)
+#define UCF64_FPSCR_FLAG_INEXACT        (1 << 22)
+#define UCF64_FPSCR_FLAG_HUGEINT        (1 << 23)
+#define UCF64_FPSCR_FLAG_DENORMAL       (1 << 24)
+#define UCF64_FPSCR_FLAG_UNIMP          (1 << 25)
+#define UCF64_FPSCR_FLAG_DIVZERO        (1 << 26)
+
+#define UC32_HWCAP_CMOV                 4 /* 1 << 2 */
+#define UC32_HWCAP_UCF64                8 /* 1 << 3 */
+
+#define UC32_CPUID(env)                 (env->cp0.c0_cpuid)
+#define UC32_CPUID_UCV2                 0x40010863
+#define UC32_CPUID_ANY                  0xffffffff
+
+#define cpu_init                        uc32_cpu_init
+#define cpu_exec                        uc32_cpu_exec
+#define cpu_signal_handler              uc32_cpu_signal_handler
+#define cpu_handle_mmu_fault            uc32_cpu_handle_mmu_fault
+
+CPUState *uc32_cpu_init(const char *cpu_model);
+int uc32_cpu_exec(CPUState *s);
+int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
+int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmuu);
+
+#define CPU_SAVE_VERSION 2
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_USER_IDX 1
+static inline int cpu_mmu_index(CPUState *env)
+{
+    return (env->uncached_asr & ASR_M) == ASR_MODE_USER ? 1 : 0;
+}
+
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp) {
+        env->regs[29] = newsp;
+    }
+    env->regs[0] = 0;
+}
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+    env->regs[16] = newtls;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->regs[31] = tb->pc;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->regs[31];
+    *cs_base = 0;
+    *flags = 0;
+    if ((env->uncached_asr & ASR_M) != ASR_MODE_USER) {
+        *flags |= (1 << 6);
+    }
+}
+
+void uc32_translate_init(void);
+void do_interrupt(CPUState *);
+void switch_mode(CPUState_UniCore32 *, int);
+
+#endif /* __CPU_UC32_H__ */
diff --git a/target-unicore32/exec.h b/target-unicore32/exec.h
new file mode 100644 (file)
index 0000000..4ab55f4
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  UniCore32 execution defines
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#ifndef __UC32_EXEC_H__
+#define __UC32_EXEC_H__
+
+#include "config.h"
+#include "dyngen-exec.h"
+
+register struct CPUState_UniCore32 *env asm(AREG0);
+
+#include "cpu.h"
+#include "exec-all.h"
+
+static inline void env_to_regs(void)
+{
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+static inline int cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request &
+        (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+}
+
+static inline int cpu_halted(CPUState *env)
+{
+    if (!env->halted) {
+        return 0;
+    }
+    /* An interrupt wakes the CPU even if the I and R ASR bits are
+       set.  We use EXITTB to silently wake CPU without causing an
+       actual interrupt.  */
+    if (cpu_has_work(env)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
+#endif /* __UC32_EXEC_H__ */
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
new file mode 100644 (file)
index 0000000..483aeae
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "helper.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+
+static inline void set_feature(CPUState *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;
+}
+
+CPUState *uc32_cpu_init(const char *cpu_model)
+{
+    CPUState *env;
+    uint32_t id;
+    static int inited = 1;
+
+    env = qemu_mallocz(sizeof(CPUState));
+    cpu_exec_init(env);
+
+    id = uc32_cpu_find_by_name(cpu_model);
+    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);
+    }
+
+    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;
+}
+
+uint32_t HELPER(clo)(uint32_t x)
+{
+    return clo32(x);
+}
+
+uint32_t HELPER(clz)(uint32_t x)
+{
+    return clz32(x);
+}
+
+void do_interrupt(CPUState *env)
+{
+    env->exception_index = -1;
+}
+
+int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmmu)
+{
+    env->exception_index = UC32_EXCP_TRAP;
+    env->cp0.c4_faultaddr = address;
+    return 1;
+}
+
+/* These should probably raise undefined insn exceptions.  */
+void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return;
+}
+
+uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return 0;
+}
+
+void HELPER(set_cp0)(CPUState *env, uint32_t insn, uint32_t val)
+{
+    cpu_abort(env, "cp0 insn %08x\n", insn);
+}
+
+uint32_t HELPER(get_cp0)(CPUState *env, uint32_t insn)
+{
+    cpu_abort(env, "cp0 insn %08x\n", insn);
+    return 0;
+}
+
+void switch_mode(CPUState *env, int mode)
+{
+    if (mode != ASR_MODE_USER) {
+        cpu_abort(env, "Tried to switch out of user mode\n");
+    }
+}
+
+void HELPER(set_r29_banked)(CPUState *env, uint32_t mode, uint32_t val)
+{
+    cpu_abort(env, "banked r29 write\n");
+}
+
+uint32_t HELPER(get_r29_banked)(CPUState *env, uint32_t mode)
+{
+    cpu_abort(env, "banked r29 read\n");
+    return 0;
+}
+
+/* UniCore-F64 support.  We follow the convention used for F64 instrunctions:
+   Single precition routines have a "s" suffix, double precision a
+   "d" suffix.  */
+
+/* Convert host exception flags to f64 form.  */
+static inline int ucf64_exceptbits_from_host(int host_bits)
+{
+    int target_bits = 0;
+
+    if (host_bits & float_flag_invalid) {
+        target_bits |= UCF64_FPSCR_FLAG_INVALID;
+    }
+    if (host_bits & float_flag_divbyzero) {
+        target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
+    }
+    if (host_bits & float_flag_overflow) {
+        target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
+    }
+    if (host_bits & float_flag_underflow) {
+        target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
+    }
+    if (host_bits & float_flag_inexact) {
+        target_bits |= UCF64_FPSCR_FLAG_INEXACT;
+    }
+    return target_bits;
+}
+
+uint32_t HELPER(ucf64_get_fpscr)(CPUState *env)
+{
+    int i;
+    uint32_t fpscr;
+
+    fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
+    i = get_float_exception_flags(&env->ucf64.fp_status);
+    fpscr |= ucf64_exceptbits_from_host(i);
+    return fpscr;
+}
+
+/* Convert ucf64 exception flags to target form.  */
+static inline int ucf64_exceptbits_to_host(int target_bits)
+{
+    int host_bits = 0;
+
+    if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
+        host_bits |= float_flag_invalid;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
+        host_bits |= float_flag_divbyzero;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
+        host_bits |= float_flag_overflow;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
+        host_bits |= float_flag_underflow;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
+        host_bits |= float_flag_inexact;
+    }
+    return host_bits;
+}
+
+void HELPER(ucf64_set_fpscr)(CPUState *env, uint32_t val)
+{
+    int i;
+    uint32_t changed;
+
+    changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
+
+    changed ^= val;
+    if (changed & (UCF64_FPSCR_RND_MASK)) {
+        i = UCF64_FPSCR_RND(val);
+        switch (i) {
+        case 0:
+            i = float_round_nearest_even;
+            break;
+        case 1:
+            i = float_round_to_zero;
+            break;
+        case 2:
+            i = float_round_up;
+            break;
+        case 3:
+            i = float_round_down;
+            break;
+        default: /* 100 and 101 not implement */
+            cpu_abort(env, "Unsupported UniCore-F64 round mode");
+        }
+        set_float_rounding_mode(i, &env->ucf64.fp_status);
+    }
+
+    i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
+    set_float_exception_flags(i, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUState *env)
+{
+    return float32_add(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUState *env)
+{
+    return float64_add(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUState *env)
+{
+    return float32_sub(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUState *env)
+{
+    return float64_sub(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUState *env)
+{
+    return float32_mul(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUState *env)
+{
+    return float64_mul(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUState *env)
+{
+    return float32_div(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUState *env)
+{
+    return float64_div(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_negs)(float32 a)
+{
+    return float32_chs(a);
+}
+
+float64 HELPER(ucf64_negd)(float64 a)
+{
+    return float64_chs(a);
+}
+
+float32 HELPER(ucf64_abss)(float32 a)
+{
+    return float32_abs(a);
+}
+
+float64 HELPER(ucf64_absd)(float64 a)
+{
+    return float64_abs(a);
+}
+
+/* XXX: check quiet/signaling case */
+void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUState *env)
+{
+    int flag;
+    flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
+    env->CF = 0;
+    switch (c & 0x7) {
+    case 0: /* F */
+        break;
+    case 1: /* UN */
+        if (flag == 2) {
+            env->CF = 1;
+        }
+        break;
+    case 2: /* EQ */
+        if (flag == 0) {
+            env->CF = 1;
+        }
+        break;
+    case 3: /* UEQ */
+        if ((flag == 0) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 4: /* OLT */
+        if (flag == -1) {
+            env->CF = 1;
+        }
+        break;
+    case 5: /* ULT */
+        if ((flag == -1) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 6: /* OLE */
+        if ((flag == -1) || (flag == 0)) {
+            env->CF = 1;
+        }
+        break;
+    case 7: /* ULE */
+        if (flag != 1) {
+            env->CF = 1;
+        }
+        break;
+    }
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+                    | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUState *env)
+{
+    int flag;
+    flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
+    env->CF = 0;
+    switch (c & 0x7) {
+    case 0: /* F */
+        break;
+    case 1: /* UN */
+        if (flag == 2) {
+            env->CF = 1;
+        }
+        break;
+    case 2: /* EQ */
+        if (flag == 0) {
+            env->CF = 1;
+        }
+        break;
+    case 3: /* UEQ */
+        if ((flag == 0) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 4: /* OLT */
+        if (flag == -1) {
+            env->CF = 1;
+        }
+        break;
+    case 5: /* ULT */
+        if ((flag == -1) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 6: /* OLE */
+        if ((flag == -1) || (flag == 0)) {
+            env->CF = 1;
+        }
+        break;
+    case 7: /* ULE */
+        if (flag != 1) {
+            env->CF = 1;
+        }
+        break;
+    }
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+                    | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+/* Helper routines to perform bitwise copies between float and int.  */
+static inline float32 ucf64_itos(uint32_t i)
+{
+    union {
+        uint32_t i;
+        float32 s;
+    } v;
+
+    v.i = i;
+    return v.s;
+}
+
+static inline uint32_t ucf64_stoi(float32 s)
+{
+    union {
+        uint32_t i;
+        float32 s;
+    } v;
+
+    v.s = s;
+    return v.i;
+}
+
+static inline float64 ucf64_itod(uint64_t i)
+{
+    union {
+        uint64_t i;
+        float64 d;
+    } v;
+
+    v.i = i;
+    return v.d;
+}
+
+static inline uint64_t ucf64_dtoi(float64 d)
+{
+    union {
+        uint64_t i;
+        float64 d;
+    } v;
+
+    v.d = d;
+    return v.i;
+}
+
+/* Integer to float conversion.  */
+float32 HELPER(ucf64_si2sf)(float32 x, CPUState *env)
+{
+    return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_si2df)(float32 x, CPUState *env)
+{
+    return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+/* Float to integer conversion.  */
+float32 HELPER(ucf64_sf2si)(float32 x, CPUState *env)
+{
+    return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
+}
+
+float32 HELPER(ucf64_df2si)(float64 x, CPUState *env)
+{
+    return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
+}
+
+/* floating point conversion */
+float64 HELPER(ucf64_sf2df)(float32 x, CPUState *env)
+{
+    return float32_to_float64(x, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_df2sf)(float64 x, CPUState *env)
+{
+    return float64_to_float32(x, &env->ucf64.fp_status);
+}
diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h
new file mode 100644 (file)
index 0000000..615de2a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#include "def-helper.h"
+
+DEF_HELPER_1(clz, i32, i32)
+DEF_HELPER_1(clo, i32, i32)
+
+DEF_HELPER_1(exception, void, i32)
+
+DEF_HELPER_2(asr_write, void, i32, i32)
+DEF_HELPER_0(asr_read, i32)
+
+DEF_HELPER_3(set_cp0, void, env, i32, i32)
+DEF_HELPER_2(get_cp0, i32, env, i32)
+
+DEF_HELPER_3(set_cp, void, env, i32, i32)
+DEF_HELPER_2(get_cp, i32, env, i32)
+
+DEF_HELPER_1(get_user_reg, i32, i32)
+DEF_HELPER_2(set_user_reg, void, i32, i32)
+
+DEF_HELPER_2(add_cc, i32, i32, i32)
+DEF_HELPER_2(adc_cc, i32, i32, i32)
+DEF_HELPER_2(sub_cc, i32, i32, i32)
+DEF_HELPER_2(sbc_cc, i32, i32, i32)
+
+DEF_HELPER_2(shl, i32, i32, i32)
+DEF_HELPER_2(shr, i32, i32, i32)
+DEF_HELPER_2(sar, i32, i32, i32)
+DEF_HELPER_2(shl_cc, i32, i32, i32)
+DEF_HELPER_2(shr_cc, i32, i32, i32)
+DEF_HELPER_2(sar_cc, i32, i32, i32)
+DEF_HELPER_2(ror_cc, i32, i32, i32)
+
+DEF_HELPER_2(get_r29_banked, i32, env, i32)
+DEF_HELPER_3(set_r29_banked, void, env, i32, i32)
+
+DEF_HELPER_1(ucf64_get_fpscr, i32, env)
+DEF_HELPER_2(ucf64_set_fpscr, void, env, i32)
+
+DEF_HELPER_3(ucf64_adds, f32, f32, f32, env)
+DEF_HELPER_3(ucf64_addd, f64, f64, f64, env)
+DEF_HELPER_3(ucf64_subs, f32, f32, f32, env)
+DEF_HELPER_3(ucf64_subd, f64, f64, f64, env)
+DEF_HELPER_3(ucf64_muls, f32, f32, f32, env)
+DEF_HELPER_3(ucf64_muld, f64, f64, f64, env)
+DEF_HELPER_3(ucf64_divs, f32, f32, f32, env)
+DEF_HELPER_3(ucf64_divd, f64, f64, f64, env)
+DEF_HELPER_1(ucf64_negs, f32, f32)
+DEF_HELPER_1(ucf64_negd, f64, f64)
+DEF_HELPER_1(ucf64_abss, f32, f32)
+DEF_HELPER_1(ucf64_absd, f64, f64)
+DEF_HELPER_4(ucf64_cmps, void, f32, f32, i32, env)
+DEF_HELPER_4(ucf64_cmpd, void, f64, f64, i32, env)
+
+DEF_HELPER_2(ucf64_sf2df, f64, f32, env)
+DEF_HELPER_2(ucf64_df2sf, f32, f64, env)
+
+DEF_HELPER_2(ucf64_si2sf, f32, f32, env)
+DEF_HELPER_2(ucf64_si2df, f64, f32, env)
+
+DEF_HELPER_2(ucf64_sf2si, f32, f32, env)
+DEF_HELPER_2(ucf64_df2si, f32, f64, env)
+
+#include "def-helper.h"
diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c
new file mode 100644 (file)
index 0000000..31e4b11
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ *  UniCore32 helper routines
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#include "exec.h"
+#include "helper.h"
+
+#define SIGNBIT (uint32_t)0x80000000
+#define SIGNBIT64 ((uint64_t)1 << 63)
+
+void HELPER(exception)(uint32_t excp)
+{
+    env->exception_index = excp;
+    cpu_loop_exit();
+}
+
+static target_ulong asr_read(void)
+{
+    int ZF;
+    ZF = (env->ZF == 0);
+    return env->uncached_asr | (env->NF & 0x80000000) | (ZF << 30) |
+        (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
+}
+
+target_ulong cpu_asr_read(CPUState *env1)
+{
+    CPUState *saved_env;
+    target_ulong ret;
+
+    saved_env = env;
+    env = env1;
+    ret = asr_read();
+    env = saved_env;
+    return ret;
+}
+
+target_ulong HELPER(asr_read)(void)
+{
+    return asr_read();
+}
+
+static void asr_write(target_ulong val, target_ulong mask)
+{
+    if (mask & ASR_NZCV) {
+        env->ZF = (~val) & ASR_Z;
+        env->NF = val;
+        env->CF = (val >> 29) & 1;
+        env->VF = (val << 3) & 0x80000000;
+    }
+
+    if ((env->uncached_asr ^ val) & mask & ASR_M) {
+        switch_mode(env, val & ASR_M);
+    }
+    mask &= ~ASR_NZCV;
+    env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask);
+}
+
+void cpu_asr_write(CPUState *env1, target_ulong val, target_ulong mask)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    asr_write(val, mask);
+    env = saved_env;
+}
+
+void HELPER(asr_write)(target_ulong val, target_ulong mask)
+{
+    asr_write(val, mask);
+}
+
+/* Access to user mode registers from privileged modes.  */
+uint32_t HELPER(get_user_reg)(uint32_t regno)
+{
+    uint32_t val;
+
+    if (regno == 29) {
+        val = env->banked_r29[0];
+    } else if (regno == 30) {
+        val = env->banked_r30[0];
+    } else {
+        val = env->regs[regno];
+    }
+    return val;
+}
+
+void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
+{
+    if (regno == 29) {
+        env->banked_r29[0] = val;
+    } else if (regno == 30) {
+        env->banked_r30[0] = val;
+    } else {
+        env->regs[regno] = val;
+    }
+}
+
+/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
+   The only way to do that in TCG is a conditional branch, which clobbers
+   all our temporaries.  For now implement these as helper functions.  */
+
+uint32_t HELPER(add_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    result = a + b;
+    env->NF = env->ZF = result;
+    env->CF = result < a;
+    env->VF = (a ^ b ^ -1) & (a ^ result);
+    return result;
+}
+
+uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    if (!env->CF) {
+        result = a + b;
+        env->CF = result < a;
+    } else {
+        result = a + b + 1;
+        env->CF = result <= a;
+    }
+    env->VF = (a ^ b ^ -1) & (a ^ result);
+    env->NF = env->ZF = result;
+    return result;
+}
+
+uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    result = a - b;
+    env->NF = env->ZF = result;
+    env->CF = a >= b;
+    env->VF = (a ^ b) & (a ^ result);
+    return result;
+}
+
+uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b)
+{
+    uint32_t result;
+    if (!env->CF) {
+        result = a - b - 1;
+        env->CF = a > b;
+    } else {
+        result = a - b;
+        env->CF = a >= b;
+    }
+    env->VF = (a ^ b) & (a ^ result);
+    env->NF = env->ZF = result;
+    return result;
+}
+
+/* Similarly for variable shift instructions.  */
+
+uint32_t HELPER(shl)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        return 0;
+    }
+    return x << shift;
+}
+
+uint32_t HELPER(shr)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        return 0;
+    }
+    return (uint32_t)x >> shift;
+}
+
+uint32_t HELPER(sar)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        shift = 31;
+    }
+    return (int32_t)x >> shift;
+}
+
+uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        if (shift == 32) {
+            env->CF = x & 1;
+        } else {
+            env->CF = 0;
+        }
+        return 0;
+    } else if (shift != 0) {
+        env->CF = (x >> (32 - shift)) & 1;
+        return x << shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        if (shift == 32) {
+            env->CF = (x >> 31) & 1;
+        } else {
+            env->CF = 0;
+        }
+        return 0;
+    } else if (shift != 0) {
+        env->CF = (x >> (shift - 1)) & 1;
+        return x >> shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i)
+{
+    int shift = i & 0xff;
+    if (shift >= 32) {
+        env->CF = (x >> 31) & 1;
+        return (int32_t)x >> 31;
+    } else if (shift != 0) {
+        env->CF = (x >> (shift - 1)) & 1;
+        return (int32_t)x >> shift;
+    }
+    return x;
+}
+
+uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
+{
+    int shift1, shift;
+    shift1 = i & 0xff;
+    shift = shift1 & 0x1f;
+    if (shift == 0) {
+        if (shift1 != 0) {
+            env->CF = (x >> 31) & 1;
+        }
+        return x;
+    } else {
+        env->CF = (x >> (shift - 1)) & 1;
+        return ((uint32_t)x >> shift) | (x << (32 - shift));
+    }
+}
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
new file mode 100644 (file)
index 0000000..98eaeb3
--- /dev/null
@@ -0,0 +1,2104 @@
+/*
+ *  UniCore32 translation
+ *
+ * Copyright (C) 2010-2011 GUAN Xue-tao
+ *
+ * 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.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+/* internal defines */
+typedef struct DisasContext {
+    target_ulong pc;
+    int is_jmp;
+    /* Nonzero if this instruction has been conditionally skipped.  */
+    int condjmp;
+    /* The label that will be jumped to when the instruction is skipped.  */
+    int condlabel;
+    struct TranslationBlock *tb;
+    int singlestep_enabled;
+} DisasContext;
+
+#define IS_USER(s) 1
+
+/* These instructions trap after executing, so defer them until after the
+   conditional executions state has been updated.  */
+#define DISAS_SYSCALL 5
+
+static TCGv_ptr cpu_env;
+static TCGv_i32 cpu_R[32];
+
+/* FIXME:  These should be removed.  */
+static TCGv cpu_F0s, cpu_F1s;
+static TCGv_i64 cpu_F0d, cpu_F1d;
+
+#include "gen-icount.h"
+
+static const char *regnames[] = {
+      "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07",
+      "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15",
+      "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+      "r24", "r25", "r26", "r27", "r28", "r29", "r30", "pc" };
+
+/* initialize TCG globals.  */
+void uc32_translate_init(void)
+{
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    for (i = 0; i < 32; i++) {
+        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                offsetof(CPUState, regs[i]), regnames[i]);
+    }
+
+#define GEN_HELPER 2
+#include "helper.h"
+}
+
+static int num_temps;
+
+/* Allocate a temporary variable.  */
+static TCGv_i32 new_tmp(void)
+{
+    num_temps++;
+    return tcg_temp_new_i32();
+}
+
+/* Release a temporary variable.  */
+static void dead_tmp(TCGv tmp)
+{
+    tcg_temp_free(tmp);
+    num_temps--;
+}
+
+static inline TCGv load_cpu_offset(int offset)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_ld_i32(tmp, cpu_env, offset);
+    return tmp;
+}
+
+#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name))
+
+static inline void store_cpu_offset(TCGv var, int offset)
+{
+    tcg_gen_st_i32(var, cpu_env, offset);
+    dead_tmp(var);
+}
+
+#define store_cpu_field(var, name) \
+    store_cpu_offset(var, offsetof(CPUState, name))
+
+/* Set a variable to the value of a CPU register.  */
+static void load_reg_var(DisasContext *s, TCGv var, int reg)
+{
+    if (reg == 31) {
+        uint32_t addr;
+        /* normaly, since we updated PC */
+        addr = (long)s->pc;
+        tcg_gen_movi_i32(var, addr);
+    } else {
+        tcg_gen_mov_i32(var, cpu_R[reg]);
+    }
+}
+
+/* Create a new temporary and set it to the value of a CPU register.  */
+static inline TCGv load_reg(DisasContext *s, int reg)
+{
+    TCGv tmp = new_tmp();
+    load_reg_var(s, tmp, reg);
+    return tmp;
+}
+
+/* Set a CPU register.  The source must be a temporary and will be
+   marked as dead.  */
+static void store_reg(DisasContext *s, int reg, TCGv var)
+{
+    if (reg == 31) {
+        tcg_gen_andi_i32(var, var, ~3);
+        s->is_jmp = DISAS_JUMP;
+    }
+    tcg_gen_mov_i32(cpu_R[reg], var);
+    dead_tmp(var);
+}
+
+/* Value extensions.  */
+#define gen_uxtb(var)           tcg_gen_ext8u_i32(var, var)
+#define gen_uxth(var)           tcg_gen_ext16u_i32(var, var)
+#define gen_sxtb(var)           tcg_gen_ext8s_i32(var, var)
+#define gen_sxth(var)           tcg_gen_ext16s_i32(var, var)
+
+#define UCOP_REG_M              (((insn) >>  0) & 0x1f)
+#define UCOP_REG_N              (((insn) >> 19) & 0x1f)
+#define UCOP_REG_D              (((insn) >> 14) & 0x1f)
+#define UCOP_REG_S              (((insn) >>  9) & 0x1f)
+#define UCOP_REG_LO             (((insn) >> 14) & 0x1f)
+#define UCOP_REG_HI             (((insn) >>  9) & 0x1f)
+#define UCOP_SH_OP              (((insn) >>  6) & 0x03)
+#define UCOP_SH_IM              (((insn) >>  9) & 0x1f)
+#define UCOP_OPCODES            (((insn) >> 25) & 0x0f)
+#define UCOP_IMM_9              (((insn) >>  0) & 0x1ff)
+#define UCOP_IMM10              (((insn) >>  0) & 0x3ff)
+#define UCOP_IMM14              (((insn) >>  0) & 0x3fff)
+#define UCOP_COND               (((insn) >> 25) & 0x0f)
+#define UCOP_CMOV_COND          (((insn) >> 19) & 0x0f)
+#define UCOP_CPNUM              (((insn) >> 10) & 0x0f)
+#define UCOP_UCF64_FMT          (((insn) >> 24) & 0x03)
+#define UCOP_UCF64_FUNC         (((insn) >>  6) & 0x0f)
+#define UCOP_UCF64_COND         (((insn) >>  6) & 0x0f)
+
+#define UCOP_SET(i)             ((insn) & (1 << (i)))
+#define UCOP_SET_P              UCOP_SET(28)
+#define UCOP_SET_U              UCOP_SET(27)
+#define UCOP_SET_B              UCOP_SET(26)
+#define UCOP_SET_W              UCOP_SET(25)
+#define UCOP_SET_L              UCOP_SET(24)
+#define UCOP_SET_S              UCOP_SET(24)
+
+#define ILLEGAL         cpu_abort(env,                                  \
+                        "Illegal UniCore32 instruction %x at line %d!", \
+                        insn, __LINE__)
+
+static inline void gen_set_asr(TCGv var, uint32_t mask)
+{
+    TCGv tmp_mask = tcg_const_i32(mask);
+    gen_helper_asr_write(var, tmp_mask);
+    tcg_temp_free_i32(tmp_mask);
+}
+/* Set NZCV flags from the high 4 bits of var.  */
+#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV)
+
+static void gen_exception(int excp)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_movi_i32(tmp, excp);
+    gen_helper_exception(tmp);
+    dead_tmp(tmp);
+}
+
+/* FIXME: Most targets have native widening multiplication.
+   It would be good to use that instead of a full wide multiply.  */
+/* 32x32->64 multiply.  Marks inputs as dead.  */
+static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
+{
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(tmp1, a);
+    dead_tmp(a);
+    tcg_gen_extu_i32_i64(tmp2, b);
+    dead_tmp(b);
+    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
+    tcg_temp_free_i64(tmp2);
+    return tmp1;
+}
+
+static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
+{
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
+
+    tcg_gen_ext_i32_i64(tmp1, a);
+    dead_tmp(a);
+    tcg_gen_ext_i32_i64(tmp2, b);
+    dead_tmp(b);
+    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
+    tcg_temp_free_i64(tmp2);
+    return tmp1;
+}
+
+#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))
+
+/* Set CF to the top bit of var.  */
+static void gen_set_CF_bit31(TCGv var)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_shri_i32(tmp, var, 31);
+    gen_set_CF(tmp);
+    dead_tmp(tmp);
+}
+
+/* Set N and Z flags from var.  */
+static inline void gen_logic_CC(TCGv var)
+{
+    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF));
+    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF));
+}
+
+/* dest = T0 + T1 + CF. */
+static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_add_i32(dest, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(dest, dest, tmp);
+    dead_tmp(tmp);
+}
+
+/* dest = T0 - T1 + CF - 1.  */
+static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_sub_i32(dest, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(dest, dest, tmp);
+    tcg_gen_subi_i32(dest, dest, 1);
+    dead_tmp(tmp);
+}
+
+static void shifter_out_im(TCGv var, int shift)
+{
+    TCGv tmp = new_tmp();
+    if (shift == 0) {
+        tcg_gen_andi_i32(tmp, var, 1);
+    } else {
+        tcg_gen_shri_i32(tmp, var, shift);
+        if (shift != 31) {
+            tcg_gen_andi_i32(tmp, tmp, 1);
+        }
+    }
+    gen_set_CF(tmp);
+    dead_tmp(tmp);
+}
+
+/* Shift by immediate.  Includes special handling for shift == 0.  */
+static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift,
+        int flags)
+{
+    switch (shiftop) {
+    case 0: /* LSL */
+        if (shift != 0) {
+            if (flags) {
+                shifter_out_im(var, 32 - shift);
+            }
+            tcg_gen_shli_i32(var, var, shift);
+        }
+        break;
+    case 1: /* LSR */
+        if (shift == 0) {
+            if (flags) {
+                tcg_gen_shri_i32(var, var, 31);
+                gen_set_CF(var);
+            }
+            tcg_gen_movi_i32(var, 0);
+        } else {
+            if (flags) {
+                shifter_out_im(var, shift - 1);
+            }
+            tcg_gen_shri_i32(var, var, shift);
+        }
+        break;
+    case 2: /* ASR */
+        if (shift == 0) {
+            shift = 32;
+        }
+        if (flags) {
+            shifter_out_im(var, shift - 1);
+        }
+        if (shift == 32) {
+            shift = 31;
+        }
+        tcg_gen_sari_i32(var, var, shift);
+        break;
+    case 3: /* ROR/RRX */
+        if (shift != 0) {
+            if (flags) {
+                shifter_out_im(var, shift - 1);
+            }
+            tcg_gen_rotri_i32(var, var, shift); break;
+        } else {
+            TCGv tmp = load_cpu_field(CF);
+            if (flags) {
+                shifter_out_im(var, 0);
+            }
+            tcg_gen_shri_i32(var, var, 1);
+            tcg_gen_shli_i32(tmp, tmp, 31);
+            tcg_gen_or_i32(var, var, tmp);
+            dead_tmp(tmp);
+        }
+    }
+};
+
+static inline void gen_uc32_shift_reg(TCGv var, int shiftop,
+                                     TCGv shift, int flags)
+{
+    if (flags) {
+        switch (shiftop) {
+        case 0:
+            gen_helper_shl_cc(var, var, shift);
+            break;
+        case 1:
+            gen_helper_shr_cc(var, var, shift);
+            break;
+        case 2:
+            gen_helper_sar_cc(var, var, shift);
+            break;
+        case 3:
+            gen_helper_ror_cc(var, var, shift);
+            break;
+        }
+    } else {
+        switch (shiftop) {
+        case 0:
+            gen_helper_shl(var, var, shift);
+            break;
+        case 1:
+            gen_helper_shr(var, var, shift);
+            break;
+        case 2:
+            gen_helper_sar(var, var, shift);
+            break;
+        case 3:
+            tcg_gen_andi_i32(shift, shift, 0x1f);
+            tcg_gen_rotr_i32(var, var, shift);
+            break;
+        }
+    }
+    dead_tmp(shift);
+}
+
+static void gen_test_cc(int cc, int label)
+{
+    TCGv tmp;
+    TCGv tmp2;
+    int inv;
+
+    switch (cc) {
+    case 0: /* eq: Z */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 1: /* ne: !Z */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        break;
+    case 2: /* cs: C */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        break;
+    case 3: /* cc: !C */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 4: /* mi: N */
+        tmp = load_cpu_field(NF);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 5: /* pl: !N */
+        tmp = load_cpu_field(NF);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 6: /* vs: V */
+        tmp = load_cpu_field(VF);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 7: /* vc: !V */
+        tmp = load_cpu_field(VF);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 8: /* hi: C && !Z */
+        inv = gen_new_label();
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
+        dead_tmp(tmp);
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
+        gen_set_label(inv);
+        break;
+    case 9: /* ls: !C || Z */
+        tmp = load_cpu_field(CF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        dead_tmp(tmp);
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        break;
+    case 10: /* ge: N == V -> N ^ V == 0 */
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        break;
+    case 11: /* lt: N != V -> N ^ V != 0 */
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    case 12: /* gt: !Z && N == V */
+        inv = gen_new_label();
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
+        dead_tmp(tmp);
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
+        gen_set_label(inv);
+        break;
+    case 13: /* le: Z || N != V */
+        tmp = load_cpu_field(ZF);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        dead_tmp(tmp);
+        tmp = load_cpu_field(VF);
+        tmp2 = load_cpu_field(NF);
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
+        break;
+    default:
+        fprintf(stderr, "Bad condition code 0x%x\n", cc);
+        abort();
+    }
+    dead_tmp(tmp);
+}
+
+static const uint8_t table_logic_cc[16] = {
+    1, /* and */    1, /* xor */    0, /* sub */    0, /* rsb */
+    0, /* add */    0, /* adc */    0, /* sbc */    0, /* rsc */
+    1, /* andl */   1, /* xorl */   0, /* cmp */    0, /* cmn */
+    1, /* orr */    1, /* mov */    1, /* bic */    1, /* mvn */
+};
+
+/* Set PC state from an immediate address.  */
+static inline void gen_bx_im(DisasContext *s, uint32_t addr)
+{
+    s->is_jmp = DISAS_UPDATE;
+    tcg_gen_movi_i32(cpu_R[31], addr & ~3);
+}
+
+/* Set PC state from var.  var is marked as dead.  */
+static inline void gen_bx(DisasContext *s, TCGv var)
+{
+    s->is_jmp = DISAS_UPDATE;
+    tcg_gen_andi_i32(cpu_R[31], var, ~3);
+    dead_tmp(var);
+}
+
+static inline void store_reg_bx(DisasContext *s, int reg, TCGv var)
+{
+    store_reg(s, reg, var);
+}
+
+static inline TCGv gen_ld8s(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld8s(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv gen_ld8u(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld8u(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv gen_ld16s(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld16s(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv gen_ld16u(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld16u(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv gen_ld32(TCGv addr, int index)
+{
+    TCGv tmp = new_tmp();
+    tcg_gen_qemu_ld32u(tmp, addr, index);
+    return tmp;
+}
+
+static inline TCGv_i64 gen_ld64(TCGv addr, int index)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_qemu_ld64(tmp, addr, index);
+    return tmp;
+}
+
+static inline void gen_st8(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st8(val, addr, index);
+    dead_tmp(val);
+}
+
+static inline void gen_st16(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st16(val, addr, index);
+    dead_tmp(val);
+}
+
+static inline void gen_st32(TCGv val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st32(val, addr, index);
+    dead_tmp(val);
+}
+
+static inline void gen_st64(TCGv_i64 val, TCGv addr, int index)
+{
+    tcg_gen_qemu_st64(val, addr, index);
+    tcg_temp_free_i64(val);
+}
+
+static inline void gen_set_pc_im(uint32_t val)
+{
+    tcg_gen_movi_i32(cpu_R[31], val);
+}
+
+/* Force a TB lookup after an instruction that changes the CPU state.  */
+static inline void gen_lookup_tb(DisasContext *s)
+{
+    tcg_gen_movi_i32(cpu_R[31], s->pc & ~1);
+    s->is_jmp = DISAS_UPDATE;
+}
+
+static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
+        TCGv var)
+{
+    int val;
+    TCGv offset;
+
+    if (UCOP_SET(29)) {
+        /* immediate */
+        val = UCOP_IMM14;
+        if (!UCOP_SET_U) {
+            val = -val;
+        }
+        if (val != 0) {
+            tcg_gen_addi_i32(var, var, val);
+        }
+    } else {
+        /* shift/register */
+        offset = load_reg(s, UCOP_REG_M);
+        gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0);
+        if (!UCOP_SET_U) {
+            tcg_gen_sub_i32(var, var, offset);
+        } else {
+            tcg_gen_add_i32(var, var, offset);
+        }
+        dead_tmp(offset);
+    }
+}
+
+static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
+        TCGv var)
+{
+    int val;
+    TCGv offset;
+
+    if (UCOP_SET(26)) {
+        /* immediate */
+        val = (insn & 0x1f) | ((insn >> 4) & 0x3e0);
+        if (!UCOP_SET_U) {
+            val = -val;
+        }
+        if (val != 0) {
+            tcg_gen_addi_i32(var, var, val);
+        }
+    } else {
+        /* register */
+        offset = load_reg(s, UCOP_REG_M);
+        if (!UCOP_SET_U) {
+            tcg_gen_sub_i32(var, var, offset);
+        } else {
+            tcg_gen_add_i32(var, var, offset);
+        }
+        dead_tmp(offset);
+    }
+}
+
+static inline long ucf64_reg_offset(int reg)
+{
+    if (reg & 1) {
+        return offsetof(CPUState, ucf64.regs[reg >> 1])
+          + offsetof(CPU_DoubleU, l.upper);
+    } else {
+        return offsetof(CPUState, ucf64.regs[reg >> 1])
+          + offsetof(CPU_DoubleU, l.lower);
+    }
+}
+
+#define ucf64_gen_ld32(reg)      load_cpu_offset(ucf64_reg_offset(reg))
+#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg))
+
+/* UniCore-F64 single load/store I_offset */
+static void do_ucf64_ldst_i(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    int offset;
+    TCGv tmp;
+    TCGv addr;
+
+    addr = load_reg(s, UCOP_REG_N);
+    if (!UCOP_SET_P && !UCOP_SET_W) {
+        ILLEGAL;
+    }
+
+    if (UCOP_SET_P) {
+        offset = UCOP_IMM10 << 2;
+        if (!UCOP_SET_U) {
+            offset = -offset;
+        }
+        if (offset != 0) {
+            tcg_gen_addi_i32(addr, addr, offset);
+        }
+    }
+
+    if (UCOP_SET_L) { /* load */
+        tmp = gen_ld32(addr, IS_USER(s));
+        ucf64_gen_st32(tmp, UCOP_REG_D);
+    } else { /* store */
+        tmp = ucf64_gen_ld32(UCOP_REG_D);
+        gen_st32(tmp, addr, IS_USER(s));
+    }
+
+    if (!UCOP_SET_P) {
+        offset = UCOP_IMM10 << 2;
+        if (!UCOP_SET_U) {
+            offset = -offset;
+        }
+        if (offset != 0) {
+            tcg_gen_addi_i32(addr, addr, offset);
+        }
+    }
+    if (UCOP_SET_W) {
+        store_reg(s, UCOP_REG_N, addr);
+    } else {
+        dead_tmp(addr);
+    }
+}
+
+/* UniCore-F64 load/store multiple words */
+static void do_ucf64_ldst_m(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int i;
+    int j, n, freg;
+    TCGv tmp;
+    TCGv addr;
+
+    if (UCOP_REG_D != 0) {
+        ILLEGAL;
+    }
+    if (UCOP_REG_N == 31) {
+        ILLEGAL;
+    }
+    if ((insn << 24) == 0) {
+        ILLEGAL;
+    }
+
+    addr = load_reg(s, UCOP_REG_N);
+
+    n = 0;
+    for (i = 0; i < 8; i++) {
+        if (UCOP_SET(i)) {
+            n++;
+        }
+    }
+
+    if (UCOP_SET_U) {
+        if (UCOP_SET_P) { /* pre increment */
+            tcg_gen_addi_i32(addr, addr, 4);
+        } /* unnecessary to do anything when post increment */
+    } else {
+        if (UCOP_SET_P) { /* pre decrement */
+            tcg_gen_addi_i32(addr, addr, -(n * 4));
+        } else { /* post decrement */
+            if (n != 1) {
+                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+            }
+        }
+    }
+
+    freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */
+
+    for (i = 0, j = 0; i < 8; i++, freg++) {
+        if (!UCOP_SET(i)) {
+            continue;
+        }
+
+        if (UCOP_SET_L) { /* load */
+            tmp = gen_ld32(addr, IS_USER(s));
+            ucf64_gen_st32(tmp, freg);
+        } else { /* store */
+            tmp = ucf64_gen_ld32(freg);
+            gen_st32(tmp, addr, IS_USER(s));
+        }
+
+        j++;
+        /* unnecessary to add after the last transfer */
+        if (j != n) {
+            tcg_gen_addi_i32(addr, addr, 4);
+        }
+    }
+
+    if (UCOP_SET_W) { /* write back */
+        if (UCOP_SET_U) {
+            if (!UCOP_SET_P) { /* post increment */
+                tcg_gen_addi_i32(addr, addr, 4);
+            } /* unnecessary to do anything when pre increment */
+        } else {
+            if (UCOP_SET_P) {
+                /* pre decrement */
+                if (n != 1) {
+                    tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+                }
+            } else {
+                /* post decrement */
+                tcg_gen_addi_i32(addr, addr, -(n * 4));
+            }
+        }
+        store_reg(s, UCOP_REG_N, addr);
+    } else {
+        dead_tmp(addr);
+    }
+}
+
+/* UniCore-F64 mrc/mcr */
+static void do_ucf64_trans(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv tmp;
+
+    if ((insn & 0xfe0003ff) == 0xe2000000) {
+        /* control register */
+        if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) {
+            ILLEGAL;
+        }
+        if (UCOP_SET(24)) {
+            /* CFF */
+            tmp = new_tmp();
+            gen_helper_ucf64_get_fpscr(tmp, cpu_env);
+            store_reg(s, UCOP_REG_D, tmp);
+        } else {
+            /* CTF */
+            tmp = load_reg(s, UCOP_REG_D);
+            gen_helper_ucf64_set_fpscr(cpu_env, tmp);
+            dead_tmp(tmp);
+            gen_lookup_tb(s);
+        }
+        return;
+    }
+    if ((insn & 0xfe0003ff) == 0xe0000000) {
+        /* general register */
+        if (UCOP_REG_D == 31) {
+            ILLEGAL;
+        }
+        if (UCOP_SET(24)) { /* MFF */
+            tmp = ucf64_gen_ld32(UCOP_REG_N);
+            store_reg(s, UCOP_REG_D, tmp);
+        } else { /* MTF */
+            tmp = load_reg(s, UCOP_REG_D);
+            ucf64_gen_st32(tmp, UCOP_REG_N);
+        }
+        return;
+    }
+    if ((insn & 0xfb000000) == 0xe9000000) {
+        /* MFFC */
+        if (UCOP_REG_D != 31) {
+            ILLEGAL;
+        }
+        if (UCOP_UCF64_COND & 0x8) {
+            ILLEGAL;
+        }
+
+        tmp = new_tmp();
+        tcg_gen_movi_i32(tmp, UCOP_UCF64_COND);
+        if (UCOP_SET(26)) {
+            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
+            tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env);
+        } else {
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
+            tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env);
+        }
+        dead_tmp(tmp);
+        return;
+    }
+    ILLEGAL;
+}
+
+/* UniCore-F64 convert instructions */
+static void do_ucf64_fcvt(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    if (UCOP_UCF64_FMT == 3) {
+        ILLEGAL;
+    }
+    if (UCOP_REG_N != 0) {
+        ILLEGAL;
+    }
+    switch (UCOP_UCF64_FUNC) {
+    case 0: /* cvt.s */
+        switch (UCOP_UCF64_FMT) {
+        case 1 /* d */:
+            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env);
+            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        case 2 /* w */:
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env);
+            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        default /* s */:
+            ILLEGAL;
+            break;
+        }
+        break;
+    case 1: /* cvt.d */
+        switch (UCOP_UCF64_FMT) {
+        case 0 /* s */:
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env);
+            tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        case 2 /* w */:
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env);
+            tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        default /* d */:
+            ILLEGAL;
+            break;
+        }
+        break;
+    case 4: /* cvt.w */
+        switch (UCOP_UCF64_FMT) {
+        case 0 /* s */:
+            tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env);
+            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+        case 1 /* d */:
+            tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+            gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env);
+            tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
+            break;
+    default /* w */:
+            ILLEGAL;
+            break;
+        }
+        break;
+    default:
+        ILLEGAL;
+    }
+}
+
+/* UniCore-F64 compare instructions */
+static void do_ucf64_fcmp(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    if (UCOP_SET(25)) {
+        ILLEGAL;
+    }
+    if (UCOP_REG_D != 0) {
+        ILLEGAL;
+    }
+
+    ILLEGAL; /* TODO */
+    if (UCOP_SET(24)) {
+        tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
+        tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+        /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */
+    } else {
+        tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
+        tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
+        /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */
+    }
+}
+
+#define gen_helper_ucf64_movs(x, y)      do { } while (0)
+#define gen_helper_ucf64_movd(x, y)      do { } while (0)
+
+#define UCF64_OP1(name)    do {                           \
+        if (UCOP_REG_N != 0) {                            \
+            ILLEGAL;                                      \
+        }                                                 \
+        switch (UCOP_UCF64_FMT) {                         \
+        case 0 /* s */:                                   \
+            tcg_gen_ld_i32(cpu_F0s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_M)); \
+            gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \
+            tcg_gen_st_i32(cpu_F0s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_D)); \
+            break;                                        \
+        case 1 /* d */:                                   \
+            tcg_gen_ld_i64(cpu_F0d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_M)); \
+            gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \
+            tcg_gen_st_i64(cpu_F0d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_D)); \
+            break;                                        \
+        case 2 /* w */:                                   \
+            ILLEGAL;                                      \
+            break;                                        \
+        }                                                 \
+    } while (0)
+
+#define UCF64_OP2(name)    do {                           \
+        switch (UCOP_UCF64_FMT) {                         \
+        case 0 /* s */:                                   \
+            tcg_gen_ld_i32(cpu_F0s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_N)); \
+            tcg_gen_ld_i32(cpu_F1s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_M)); \
+            gen_helper_ucf64_##name##s(cpu_F0s,           \
+                           cpu_F0s, cpu_F1s, cpu_env);    \
+            tcg_gen_st_i32(cpu_F0s, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_D)); \
+            break;                                        \
+        case 1 /* d */:                                   \
+            tcg_gen_ld_i64(cpu_F0d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_N)); \
+            tcg_gen_ld_i64(cpu_F1d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_M)); \
+            gen_helper_ucf64_##name##d(cpu_F0d,           \
+                           cpu_F0d, cpu_F1d, cpu_env);    \
+            tcg_gen_st_i64(cpu_F0d, cpu_env,              \
+                           ucf64_reg_offset(UCOP_REG_D)); \
+            break;                                        \
+        case 2 /* w */:                                   \
+            ILLEGAL;                                      \
+            break;                                        \
+        }                                                 \
+    } while (0)
+
+/* UniCore-F64 data processing */
+static void do_ucf64_datap(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    if (UCOP_UCF64_FMT == 3) {
+        ILLEGAL;
+    }
+    switch (UCOP_UCF64_FUNC) {
+    case 0: /* add */
+        UCF64_OP2(add);
+        break;
+    case 1: /* sub */
+        UCF64_OP2(sub);
+        break;
+    case 2: /* mul */
+        UCF64_OP2(mul);
+        break;
+    case 4: /* div */
+        UCF64_OP2(div);
+        break;
+    case 5: /* abs */
+        UCF64_OP1(abs);
+        break;
+    case 6: /* mov */
+        UCF64_OP1(mov);
+        break;
+    case 7: /* neg */
+        UCF64_OP1(neg);
+        break;
+    default:
+        ILLEGAL;
+    }
+}
+
+/* Disassemble an F64 instruction */
+static void disas_ucf64_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    if (!UCOP_SET(29)) {
+        if (UCOP_SET(26)) {
+            do_ucf64_ldst_m(env, s, insn);
+        } else {
+            do_ucf64_ldst_i(env, s, insn);
+        }
+    } else {
+        if (UCOP_SET(5)) {
+            switch ((insn >> 26) & 0x3) {
+            case 0:
+                do_ucf64_datap(env, s, insn);
+                break;
+            case 1:
+                ILLEGAL;
+                break;
+            case 2:
+                do_ucf64_fcvt(env, s, insn);
+                break;
+            case 3:
+                do_ucf64_fcmp(env, s, insn);
+                break;
+            }
+        } else {
+            do_ucf64_trans(env, s, insn);
+        }
+    }
+}
+
+static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
+{
+    TranslationBlock *tb;
+
+    tb = s->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        tcg_gen_goto_tb(n);
+        gen_set_pc_im(dest);
+        tcg_gen_exit_tb((long)tb + n);
+    } else {
+        gen_set_pc_im(dest);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static inline void gen_jmp(DisasContext *s, uint32_t dest)
+{
+    if (unlikely(s->singlestep_enabled)) {
+        /* An indirect jump so that we still trigger the debug exception.  */
+        gen_bx_im(s, dest);
+    } else {
+        gen_goto_tb(s, 0, dest);
+        s->is_jmp = DISAS_TB_JUMP;
+    }
+}
+
+static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
+{
+    if (x) {
+        tcg_gen_sari_i32(t0, t0, 16);
+    } else {
+        gen_sxth(t0);
+    }
+    if (y) {
+        tcg_gen_sari_i32(t1, t1, 16);
+    } else {
+        gen_sxth(t1);
+    }
+    tcg_gen_mul_i32(t0, t0, t1);
+}
+
+/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
+static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0)
+{
+    TCGv tmp;
+    if (bsr) {
+        /* ??? This is also undefined in system mode.  */
+        if (IS_USER(s)) {
+            return 1;
+        }
+
+        tmp = load_cpu_field(bsr);
+        tcg_gen_andi_i32(tmp, tmp, ~mask);
+        tcg_gen_andi_i32(t0, t0, mask);
+        tcg_gen_or_i32(tmp, tmp, t0);
+        store_cpu_field(tmp, bsr);
+    } else {
+        gen_set_asr(t0, mask);
+    }
+    dead_tmp(t0);
+    gen_lookup_tb(s);
+    return 0;
+}
+
+/* Generate an old-style exception return. Marks pc as dead. */
+static void gen_exception_return(DisasContext *s, TCGv pc)
+{
+    TCGv tmp;
+    store_reg(s, 31, pc);
+    tmp = load_cpu_field(bsr);
+    gen_set_asr(tmp, 0xffffffff);
+    dead_tmp(tmp);
+    s->is_jmp = DISAS_UPDATE;
+}
+
+static void disas_coproc_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    switch (UCOP_CPNUM) {
+    case 2:
+        disas_ucf64_insn(env, s, insn);
+        break;
+    default:
+        /* Unknown coprocessor. */
+        cpu_abort(env, "Unknown coprocessor!");
+    }
+}
+
+
+/* Store a 64-bit value to a register pair.  Clobbers val.  */
+static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
+{
+    TCGv tmp;
+    tmp = new_tmp();
+    tcg_gen_trunc_i64_i32(tmp, val);
+    store_reg(s, rlow, tmp);
+    tmp = new_tmp();
+    tcg_gen_shri_i64(val, val, 32);
+    tcg_gen_trunc_i64_i32(tmp, val);
+    store_reg(s, rhigh, tmp);
+}
+
+/* load and add a 64-bit value from a register pair.  */
+static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
+{
+    TCGv_i64 tmp;
+    TCGv tmpl;
+    TCGv tmph;
+
+    /* Load 64-bit value rd:rn.  */
+    tmpl = load_reg(s, rlow);
+    tmph = load_reg(s, rhigh);
+    tmp = tcg_temp_new_i64();
+    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
+    dead_tmp(tmpl);
+    dead_tmp(tmph);
+    tcg_gen_add_i64(val, val, tmp);
+    tcg_temp_free_i64(tmp);
+}
+
+/* data processing instructions */
+static void do_datap(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv tmp;
+    TCGv tmp2;
+    int logic_cc;
+
+    if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) {
+        if (UCOP_SET(23)) { /* CMOV instructions */
+            if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) {
+                ILLEGAL;
+            }
+            /* if not always execute, we generate a conditional jump to
+               next instruction */
+            s->condlabel = gen_new_label();
+            gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel);
+            s->condjmp = 1;
+        }
+    }
+
+    logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24);
+
+    if (UCOP_SET(29)) {
+        unsigned int val;
+        /* immediate operand */
+        val = UCOP_IMM_9;
+        if (UCOP_SH_IM) {
+            val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
+        }
+        tmp2 = new_tmp();
+        tcg_gen_movi_i32(tmp2, val);
+        if (logic_cc && UCOP_SH_IM) {
+            gen_set_CF_bit31(tmp2);
+        }
+   } else {
+        /* register */
+        tmp2 = load_reg(s, UCOP_REG_M);
+        if (UCOP_SET(5)) {
+            tmp = load_reg(s, UCOP_REG_S);
+            gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc);
+        } else {
+            gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc);
+        }
+    }
+
+    if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
+        tmp = load_reg(s, UCOP_REG_N);
+    } else {
+        TCGV_UNUSED(tmp);
+    }
+
+    switch (UCOP_OPCODES) {
+    case 0x00:
+        tcg_gen_and_i32(tmp, tmp, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x01:
+        tcg_gen_xor_i32(tmp, tmp, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x02:
+        if (UCOP_SET_S && UCOP_REG_D == 31) {
+            /* SUBS r31, ... is used for exception return.  */
+            if (IS_USER(s)) {
+                ILLEGAL;
+            }
+            gen_helper_sub_cc(tmp, tmp, tmp2);
+            gen_exception_return(s, tmp);
+        } else {
+            if (UCOP_SET_S) {
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+            } else {
+                tcg_gen_sub_i32(tmp, tmp, tmp2);
+            }
+            store_reg_bx(s, UCOP_REG_D, tmp);
+        }
+        break;
+    case 0x03:
+        if (UCOP_SET_S) {
+            gen_helper_sub_cc(tmp, tmp2, tmp);
+        } else {
+            tcg_gen_sub_i32(tmp, tmp2, tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x04:
+        if (UCOP_SET_S) {
+            gen_helper_add_cc(tmp, tmp, tmp2);
+        } else {
+            tcg_gen_add_i32(tmp, tmp, tmp2);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x05:
+        if (UCOP_SET_S) {
+            gen_helper_adc_cc(tmp, tmp, tmp2);
+        } else {
+            gen_add_carry(tmp, tmp, tmp2);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x06:
+        if (UCOP_SET_S) {
+            gen_helper_sbc_cc(tmp, tmp, tmp2);
+        } else {
+            gen_sub_carry(tmp, tmp, tmp2);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x07:
+        if (UCOP_SET_S) {
+            gen_helper_sbc_cc(tmp, tmp2, tmp);
+        } else {
+            gen_sub_carry(tmp, tmp2, tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x08:
+        if (UCOP_SET_S) {
+            tcg_gen_and_i32(tmp, tmp, tmp2);
+            gen_logic_CC(tmp);
+        }
+        dead_tmp(tmp);
+        break;
+    case 0x09:
+        if (UCOP_SET_S) {
+            tcg_gen_xor_i32(tmp, tmp, tmp2);
+            gen_logic_CC(tmp);
+        }
+        dead_tmp(tmp);
+        break;
+    case 0x0a:
+        if (UCOP_SET_S) {
+            gen_helper_sub_cc(tmp, tmp, tmp2);
+        }
+        dead_tmp(tmp);
+        break;
+    case 0x0b:
+        if (UCOP_SET_S) {
+            gen_helper_add_cc(tmp, tmp, tmp2);
+        }
+        dead_tmp(tmp);
+        break;
+    case 0x0c:
+        tcg_gen_or_i32(tmp, tmp, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    case 0x0d:
+        if (logic_cc && UCOP_REG_D == 31) {
+            /* MOVS r31, ... is used for exception return.  */
+            if (IS_USER(s)) {
+                ILLEGAL;
+            }
+            gen_exception_return(s, tmp2);
+        } else {
+            if (logic_cc) {
+                gen_logic_CC(tmp2);
+            }
+            store_reg_bx(s, UCOP_REG_D, tmp2);
+        }
+        break;
+    case 0x0e:
+        tcg_gen_andc_i32(tmp, tmp, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp);
+        break;
+    default:
+    case 0x0f:
+        tcg_gen_not_i32(tmp2, tmp2);
+        if (logic_cc) {
+            gen_logic_CC(tmp2);
+        }
+        store_reg_bx(s, UCOP_REG_D, tmp2);
+        break;
+    }
+    if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
+        dead_tmp(tmp2);
+    }
+}
+
+/* multiply */
+static void do_mult(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv tmp;
+    TCGv tmp2;
+    TCGv_i64 tmp64;
+
+    if (UCOP_SET(27)) {
+        /* 64 bit mul */
+        tmp = load_reg(s, UCOP_REG_M);
+        tmp2 = load_reg(s, UCOP_REG_N);
+        if (UCOP_SET(26)) {
+            tmp64 = gen_muls_i64_i32(tmp, tmp2);
+        } else {
+            tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+        }
+        if (UCOP_SET(25)) { /* mult accumulate */
+            gen_addq(s, tmp64, UCOP_REG_LO, UCOP_REG_HI);
+        }
+        gen_storeq_reg(s, UCOP_REG_LO, UCOP_REG_HI, tmp64);
+        tcg_temp_free_i64(tmp64);
+    } else {
+        /* 32 bit mul */
+        tmp = load_reg(s, UCOP_REG_M);
+        tmp2 = load_reg(s, UCOP_REG_N);
+        tcg_gen_mul_i32(tmp, tmp, tmp2);
+        dead_tmp(tmp2);
+        if (UCOP_SET(25)) {
+            /* Add */
+            tmp2 = load_reg(s, UCOP_REG_S);
+            tcg_gen_add_i32(tmp, tmp, tmp2);
+            dead_tmp(tmp2);
+        }
+        if (UCOP_SET_S) {
+            gen_logic_CC(tmp);
+        }
+        store_reg(s, UCOP_REG_D, tmp);
+    }
+}
+
+/* miscellaneous instructions */
+static void do_misc(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int val;
+    TCGv tmp;
+
+    if ((insn & 0xffffffe0) == 0x10ffc120) {
+        /* Trivial implementation equivalent to bx.  */
+        tmp = load_reg(s, UCOP_REG_M);
+        gen_bx(s, tmp);
+        return;
+    }
+
+    if ((insn & 0xfbffc000) == 0x30ffc000) {
+        /* PSR = immediate */
+        val = UCOP_IMM_9;
+        if (UCOP_SH_IM) {
+            val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
+        }
+        tmp = new_tmp();
+        tcg_gen_movi_i32(tmp, val);
+        if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
+            ILLEGAL;
+        }
+        return;
+    }
+
+    if ((insn & 0xfbffffe0) == 0x12ffc020) {
+        /* PSR.flag = reg */
+        tmp = load_reg(s, UCOP_REG_M);
+        if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) {
+            ILLEGAL;
+        }
+        return;
+    }
+
+    if ((insn & 0xfbffffe0) == 0x10ffc020) {
+        /* PSR = reg */
+        tmp = load_reg(s, UCOP_REG_M);
+        if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
+            ILLEGAL;
+        }
+        return;
+    }
+
+    if ((insn & 0xfbf83fff) == 0x10f80000) {
+        /* reg = PSR */
+        if (UCOP_SET_B) {
+            if (IS_USER(s)) {
+                ILLEGAL;
+            }
+            tmp = load_cpu_field(bsr);
+        } else {
+            tmp = new_tmp();
+            gen_helper_asr_read(tmp);
+        }
+        store_reg(s, UCOP_REG_D, tmp);
+        return;
+    }
+
+    if ((insn & 0xfbf83fe0) == 0x12f80120) {
+        /* clz */
+        tmp = load_reg(s, UCOP_REG_M);
+        if (UCOP_SET(26)) {
+            gen_helper_clo(tmp, tmp);
+        } else {
+            gen_helper_clz(tmp, tmp);
+        }
+        store_reg(s, UCOP_REG_D, tmp);
+        return;
+    }
+
+    /* otherwise */
+    ILLEGAL;
+}
+
+/* load/store I_offset and R_offset */
+static void do_ldst_ir(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int i;
+    TCGv tmp;
+    TCGv tmp2;
+
+    tmp2 = load_reg(s, UCOP_REG_N);
+    i = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
+
+    /* immediate */
+    if (UCOP_SET_P) {
+        gen_add_data_offset(s, insn, tmp2);
+    }
+
+    if (UCOP_SET_L) {
+        /* load */
+        if (UCOP_SET_B) {
+            tmp = gen_ld8u(tmp2, i);
+        } else {
+            tmp = gen_ld32(tmp2, i);
+        }
+    } else {
+        /* store */
+        tmp = load_reg(s, UCOP_REG_D);
+        if (UCOP_SET_B) {
+            gen_st8(tmp, tmp2, i);
+        } else {
+            gen_st32(tmp, tmp2, i);
+        }
+    }
+    if (!UCOP_SET_P) {
+        gen_add_data_offset(s, insn, tmp2);
+        store_reg(s, UCOP_REG_N, tmp2);
+    } else if (UCOP_SET_W) {
+        store_reg(s, UCOP_REG_N, tmp2);
+    } else {
+        dead_tmp(tmp2);
+    }
+    if (UCOP_SET_L) {
+        /* Complete the load.  */
+        if (UCOP_REG_D == 31) {
+            gen_bx(s, tmp);
+        } else {
+            store_reg(s, UCOP_REG_D, tmp);
+        }
+    }
+}
+
+/* SWP instruction */
+static void do_swap(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv addr;
+    TCGv tmp;
+    TCGv tmp2;
+
+    if ((insn & 0xff003fe0) != 0x40000120) {
+        ILLEGAL;
+    }
+
+    /* ??? This is not really atomic.  However we know
+       we never have multiple CPUs running in parallel,
+       so it is good enough.  */
+    addr = load_reg(s, UCOP_REG_N);
+    tmp = load_reg(s, UCOP_REG_M);
+    if (UCOP_SET_B) {
+        tmp2 = gen_ld8u(addr, IS_USER(s));
+        gen_st8(tmp, addr, IS_USER(s));
+    } else {
+        tmp2 = gen_ld32(addr, IS_USER(s));
+        gen_st32(tmp, addr, IS_USER(s));
+    }
+    dead_tmp(addr);
+    store_reg(s, UCOP_REG_D, tmp2);
+}
+
+/* load/store hw/sb */
+static void do_ldst_hwsb(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    TCGv addr;
+    TCGv tmp;
+
+    if (UCOP_SH_OP == 0) {
+        do_swap(env, s, insn);
+        return;
+    }
+
+    addr = load_reg(s, UCOP_REG_N);
+    if (UCOP_SET_P) {
+        gen_add_datah_offset(s, insn, addr);
+    }
+
+    if (UCOP_SET_L) { /* load */
+        switch (UCOP_SH_OP) {
+        case 1:
+            tmp = gen_ld16u(addr, IS_USER(s));
+            break;
+        case 2:
+            tmp = gen_ld8s(addr, IS_USER(s));
+            break;
+        default: /* see do_swap */
+        case 3:
+            tmp = gen_ld16s(addr, IS_USER(s));
+            break;
+        }
+    } else { /* store */
+        if (UCOP_SH_OP != 1) {
+            ILLEGAL;
+        }
+        tmp = load_reg(s, UCOP_REG_D);
+        gen_st16(tmp, addr, IS_USER(s));
+    }
+    /* Perform base writeback before the loaded value to
+       ensure correct behavior with overlapping index registers. */
+    if (!UCOP_SET_P) {
+        gen_add_datah_offset(s, insn, addr);
+        store_reg(s, UCOP_REG_N, addr);
+    } else if (UCOP_SET_W) {
+        store_reg(s, UCOP_REG_N, addr);
+    } else {
+        dead_tmp(addr);
+    }
+    if (UCOP_SET_L) {
+        /* Complete the load.  */
+        store_reg(s, UCOP_REG_D, tmp);
+    }
+}
+
+/* load/store multiple words */
+static void do_ldst_m(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int val, i;
+    int j, n, reg, user, loaded_base;
+    TCGv tmp;
+    TCGv tmp2;
+    TCGv addr;
+    TCGv loaded_var;
+
+    if (UCOP_SET(7)) {
+        ILLEGAL;
+    }
+    /* XXX: store correct base if write back */
+    user = 0;
+    if (UCOP_SET_B) { /* S bit in instruction table */
+        if (IS_USER(s)) {
+            ILLEGAL; /* only usable in supervisor mode */
+        }
+        if (UCOP_SET(18) == 0) { /* pc reg */
+            user = 1;
+        }
+    }
+
+    addr = load_reg(s, UCOP_REG_N);
+
+    /* compute total size */
+    loaded_base = 0;
+    TCGV_UNUSED(loaded_var);
+    n = 0;
+    for (i = 0; i < 6; i++) {
+        if (UCOP_SET(i)) {
+            n++;
+        }
+    }
+    for (i = 9; i < 19; i++) {
+        if (UCOP_SET(i)) {
+            n++;
+        }
+    }
+    /* XXX: test invalid n == 0 case ? */
+    if (UCOP_SET_U) {
+        if (UCOP_SET_P) {
+            /* pre increment */
+            tcg_gen_addi_i32(addr, addr, 4);
+        } else {
+            /* post increment */
+        }
+    } else {
+        if (UCOP_SET_P) {
+            /* pre decrement */
+            tcg_gen_addi_i32(addr, addr, -(n * 4));
+        } else {
+            /* post decrement */
+            if (n != 1) {
+                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+            }
+        }
+    }
+
+    j = 0;
+    reg = UCOP_SET(6) ? 16 : 0;
+    for (i = 0; i < 19; i++, reg++) {
+        if (i == 6) {
+            i = i + 3;
+        }
+        if (UCOP_SET(i)) {
+            if (UCOP_SET_L) { /* load */
+                tmp = gen_ld32(addr, IS_USER(s));
+                if (reg == 31) {
+                    gen_bx(s, tmp);
+                } else if (user) {
+                    tmp2 = tcg_const_i32(reg);
+                    gen_helper_set_user_reg(tmp2, tmp);
+                    tcg_temp_free_i32(tmp2);
+                    dead_tmp(tmp);
+                } else if (reg == UCOP_REG_N) {
+                    loaded_var = tmp;
+                    loaded_base = 1;
+                } else {
+                    store_reg(s, reg, tmp);
+                }
+            } else { /* store */
+                if (reg == 31) {
+                    /* special case: r31 = PC + 4 */
+                    val = (long)s->pc;
+                    tmp = new_tmp();
+                    tcg_gen_movi_i32(tmp, val);
+                } else if (user) {
+                    tmp = new_tmp();
+                    tmp2 = tcg_const_i32(reg);
+                    gen_helper_get_user_reg(tmp, tmp2);
+                    tcg_temp_free_i32(tmp2);
+                } else {
+                    tmp = load_reg(s, reg);
+                }
+                gen_st32(tmp, addr, IS_USER(s));
+            }
+            j++;
+            /* no need to add after the last transfer */
+            if (j != n) {
+                tcg_gen_addi_i32(addr, addr, 4);
+            }
+        }
+    }
+    if (UCOP_SET_W) { /* write back */
+        if (UCOP_SET_U) {
+            if (UCOP_SET_P) {
+                /* pre increment */
+            } else {
+                /* post increment */
+                tcg_gen_addi_i32(addr, addr, 4);
+            }
+        } else {
+            if (UCOP_SET_P) {
+                /* pre decrement */
+                if (n != 1) {
+                    tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+                }
+            } else {
+                /* post decrement */
+                tcg_gen_addi_i32(addr, addr, -(n * 4));
+            }
+        }
+        store_reg(s, UCOP_REG_N, addr);
+    } else {
+        dead_tmp(addr);
+    }
+    if (loaded_base) {
+        store_reg(s, UCOP_REG_N, loaded_var);
+    }
+    if (UCOP_SET_B && !user) {
+        /* Restore ASR from BSR.  */
+        tmp = load_cpu_field(bsr);
+        gen_set_asr(tmp, 0xffffffff);
+        dead_tmp(tmp);
+        s->is_jmp = DISAS_UPDATE;
+    }
+}
+
+/* branch (and link) */
+static void do_branch(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    unsigned int val;
+    int32_t offset;
+    TCGv tmp;
+
+    if (UCOP_COND == 0xf) {
+        ILLEGAL;
+    }
+
+    if (UCOP_COND != 0xe) {
+        /* if not always execute, we generate a conditional jump to
+           next instruction */
+        s->condlabel = gen_new_label();
+        gen_test_cc(UCOP_COND ^ 1, s->condlabel);
+        s->condjmp = 1;
+    }
+
+    val = (int32_t)s->pc;
+    if (UCOP_SET_L) {
+        tmp = new_tmp();
+        tcg_gen_movi_i32(tmp, val);
+        store_reg(s, 30, tmp);
+    }
+    offset = (((int32_t)insn << 8) >> 8);
+    val += (offset << 2); /* unicore is pc+4 */
+    gen_jmp(s, val);
+}
+
+static void disas_uc32_insn(CPUState *env, DisasContext *s)
+{
+    unsigned int insn;
+
+    insn = ldl_code(s->pc);
+    s->pc += 4;
+
+    /* UniCore instructions class:
+     * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx
+     * AAA  : see switch case
+     * BBBB : opcodes or cond or PUBW
+     * C    : S OR L
+     * D    : 8
+     * E    : 5
+     */
+    switch (insn >> 29) {
+    case 0b000:
+        if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) {
+            do_mult(env, s, insn);
+            break;
+        }
+
+        if (UCOP_SET(8)) {
+            do_misc(env, s, insn);
+            break;
+        }
+    case 0b001:
+        if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) {
+            do_misc(env, s, insn);
+            break;
+        }
+        do_datap(env, s, insn);
+        break;
+
+    case 0b010:
+        if (UCOP_SET(8) && UCOP_SET(5)) {
+            do_ldst_hwsb(env, s, insn);
+            break;
+        }
+        if (UCOP_SET(8) || UCOP_SET(5)) {
+            ILLEGAL;
+        }
+    case 0b011:
+        do_ldst_ir(env, s, insn);
+        break;
+
+    case 0b100:
+        if (UCOP_SET(8)) {
+            ILLEGAL; /* extended instructions */
+        }
+        do_ldst_m(env, s, insn);
+        break;
+    case 0b101:
+        do_branch(env, s, insn);
+        break;
+    case 0b110:
+        /* Coprocessor.  */
+        disas_coproc_insn(env, s, insn);
+        break;
+    case 0b111:
+        if (!UCOP_SET(28)) {
+            disas_coproc_insn(env, s, insn);
+            break;
+        }
+        if ((insn & 0xff000000) == 0xff000000) { /* syscall */
+            gen_set_pc_im(s->pc);
+            s->is_jmp = DISAS_SYSCALL;
+            break;
+        }
+        ILLEGAL;
+    }
+
+    return;
+}
+
+/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
+   basic block 'tb'. If search_pc is TRUE, also generate PC
+   information for each intermediate instruction. */
+static inline void gen_intermediate_code_internal(CPUState *env,
+        TranslationBlock *tb, int search_pc)
+{
+    DisasContext dc1, *dc = &dc1;
+    CPUBreakpoint *bp;
+    uint16_t *gen_opc_end;
+    int j, lj;
+    target_ulong pc_start;
+    uint32_t next_page_start;
+    int num_insns;
+    int max_insns;
+
+    /* generate intermediate code */
+    num_temps = 0;
+
+    pc_start = tb->pc;
+
+    dc->tb = tb;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    dc->is_jmp = DISAS_NEXT;
+    dc->pc = pc_start;
+    dc->singlestep_enabled = env->singlestep_enabled;
+    dc->condjmp = 0;
+    cpu_F0s = tcg_temp_new_i32();
+    cpu_F1s = tcg_temp_new_i32();
+    cpu_F0d = tcg_temp_new_i64();
+    cpu_F1d = tcg_temp_new_i64();
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    lj = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    gen_icount_start();
+    do {
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == dc->pc) {
+                    gen_set_pc_im(dc->pc);
+                    gen_exception(EXCP_DEBUG);
+                    dc->is_jmp = DISAS_JUMP;
+                    /* Advance PC so that clearing the breakpoint will
+                       invalidate this TB.  */
+                    dc->pc += 2; /* FIXME */
+                    goto done_generating;
+                    break;
+                }
+            }
+        }
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j) {
+                    gen_opc_instr_start[lj++] = 0;
+                }
+            }
+            gen_opc_pc[lj] = dc->pc;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
+        }
+
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        disas_uc32_insn(env, dc);
+
+        if (num_temps) {
+            fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
+            num_temps = 0;
+        }
+
+        if (dc->condjmp && !dc->is_jmp) {
+            gen_set_label(dc->condlabel);
+            dc->condjmp = 0;
+        }
+        /* Translation stops when a conditional branch is encountered.
+         * Otherwise the subsequent code could get translated several times.
+         * Also stop translation when a page boundary is reached.  This
+         * ensures prefetch aborts occur at the right place.  */
+        num_insns++;
+    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
+             !env->singlestep_enabled &&
+             !singlestep &&
+             dc->pc < next_page_start &&
+             num_insns < max_insns);
+
+    if (tb->cflags & CF_LAST_IO) {
+        if (dc->condjmp) {
+            /* FIXME:  This can theoretically happen with self-modifying
+               code.  */
+            cpu_abort(env, "IO on conditional branch instruction");
+        }
+        gen_io_end();
+    }
+
+    /* At this stage dc->condjmp will only be set when the skipped
+       instruction was a conditional branch or trap, and the PC has
+       already been written.  */
+    if (unlikely(env->singlestep_enabled)) {
+        /* Make sure the pc is updated, and raise a debug exception.  */
+        if (dc->condjmp) {
+            if (dc->is_jmp == DISAS_SYSCALL) {
+                gen_exception(UC32_EXCP_PRIV);
+            } else {
+                gen_exception(EXCP_DEBUG);
+            }
+            gen_set_label(dc->condlabel);
+        }
+        if (dc->condjmp || !dc->is_jmp) {
+            gen_set_pc_im(dc->pc);
+            dc->condjmp = 0;
+        }
+        if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) {
+            gen_exception(UC32_EXCP_PRIV);
+        } else {
+            gen_exception(EXCP_DEBUG);
+        }
+    } else {
+        /* While branches must always occur at the end of an IT block,
+           there are a few other things that can cause us to terminate
+           the TB in the middel of an IT block:
+            - Exception generating instructions (bkpt, swi, undefined).
+            - Page boundaries.
+            - Hardware watchpoints.
+           Hardware breakpoints have already been handled and skip this code.
+         */
+        switch (dc->is_jmp) {
+        case DISAS_NEXT:
+            gen_goto_tb(dc, 1, dc->pc);
+            break;
+        default:
+        case DISAS_JUMP:
+        case DISAS_UPDATE:
+            /* indicate that the hash table must be used to find the next TB */
+            tcg_gen_exit_tb(0);
+            break;
+        case DISAS_TB_JUMP:
+            /* nothing more to generate */
+            break;
+        case DISAS_SYSCALL:
+            gen_exception(UC32_EXCP_PRIV);
+            break;
+        }
+        if (dc->condjmp) {
+            gen_set_label(dc->condlabel);
+            gen_goto_tb(dc, 1, dc->pc);
+            dc->condjmp = 0;
+        }
+    }
+
+done_generating:
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+
+#ifdef DEBUG_DISAS
+    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, 0);
+        qemu_log("\n");
+    }
+#endif
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j) {
+            gen_opc_instr_start[lj++] = 0;
+        }
+    } else {
+        tb->size = dc->pc - pc_start;
+        tb->icount = num_insns;
+    }
+}
+
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+static const char *cpu_mode_names[16] = {
+    "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP",
+    "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR"
+};
+
+#define UCF64_DUMP_STATE
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+        int flags)
+{
+    int i;
+#ifdef UCF64_DUMP_STATE
+    union {
+        uint32_t i;
+        float s;
+    } s0, s1;
+    CPU_DoubleU d;
+    /* ??? This assumes float64 and double have the same layout.
+       Oh well, it's only debug dumps.  */
+    union {
+        float64 f64;
+        double d;
+    } d0;
+#endif
+    uint32_t psr;
+
+    for (i = 0; i < 32; i++) {
+        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
+        if ((i % 4) == 3) {
+            cpu_fprintf(f, "\n");
+        } else {
+            cpu_fprintf(f, " ");
+        }
+    }
+    psr = cpu_asr_read(env);
+    cpu_fprintf(f, "PSR=%08x %c%c%c%c %s\n",
+                psr,
+                psr & (1 << 31) ? 'N' : '-',
+                psr & (1 << 30) ? 'Z' : '-',
+                psr & (1 << 29) ? 'C' : '-',
+                psr & (1 << 28) ? 'V' : '-',
+                cpu_mode_names[psr & 0xf]);
+
+#ifdef UCF64_DUMP_STATE
+    for (i = 0; i < 16; i++) {
+        d.d = env->ucf64.regs[i];
+        s0.i = d.l.lower;
+        s1.i = d.l.upper;
+        d0.f64 = d.d;
+        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%" PRIx64 "(%8g)\n",
+                    i * 2, (int)s0.i, s0.s,
+                    i * 2 + 1, (int)s1.i, s1.s,
+                    i, (uint64_t)d0.f64, d0.d);
+    }
+    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
+#endif
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->regs[31] = gen_opc_pc[pc_pos];
+}
index 1d71e0bddb08cae20851e4006d98f7fb7a4a4331..fdcf4c5c3fc18e3cd839c7ad2963eedf7b4779c5 100644 (file)
@@ -27,7 +27,7 @@ int main (int argc, char *argv[])
   f = fopen (fnam, "rb");
   if (f == NULL)
     abort ();
-  close (f);
+  fclose(f);
 
   /* Cover another execution path.  */
   if (fopen ("/nonexistent", "rb") != NULL
index f44a8f34bb27771fac6958a73fc92ee108e6f4a7..5d56189f8eaa77225b478f1391926feccc9b4a14 100644 (file)
@@ -10,7 +10,7 @@ int main (int argc, char *argv[])
   FILE *f = fopen ("check_openpf2.c", "rb");
   if (f == NULL)
     abort ();
-  close (f);
+  fclose(f);
   printf ("pass\n");
   return 0;
 }
index 3b5b217a1cfc833672dfb30dac396e14e36625c4..36a9d5d2744b614901835b288dbc2fc86b09c0cd 100644 (file)
@@ -13,7 +13,7 @@ int main (int argc, char *argv[])
   char path[1024] = "/";
   struct stat buf;
 
-  strcat (path, argv[0]);
+  strncat(path, argv[0], sizeof(path) - 2);
   if (stat (".", &buf) != 0
       || !S_ISDIR (buf.st_mode))
     abort ();
index e1955cab3471d83e7fd1913b3f0c3c73c1337f81..04f21fe7c4f53e042b9cf230d576495aaf009180 100644 (file)
@@ -15,7 +15,7 @@ int main (int argc, char *argv[])
   char path[1024] = "/";
   struct stat buf;
 
-  strcat (path, argv[0]);
+  strncat(path, argv[0], sizeof(path) - 2);
   if (lstat (".", &buf) != 0
       || !S_ISDIR (buf.st_mode))
     abort ();
index fcb365f40ccd75255b465532c061b8480c8ea841..c578e2572acb6c00ea7c4bbc653d7d5bc9b4e7d0 100644 (file)
@@ -164,6 +164,7 @@ void check_aligned_anonymous_unfixed_colliding_mmaps(void)
                nlen = pagesize * 8;
                p3 = mmap(NULL, nlen, PROT_READ, 
                          MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+               fail_unless (p3 != MAP_FAILED);
 
                /* Check if the mmaped areas collide.  */
                if (p3 < p2 
@@ -174,7 +175,6 @@ void check_aligned_anonymous_unfixed_colliding_mmaps(void)
 
                /* Make sure we get pages aligned with the pagesize. The
                   target expects this.  */
-               fail_unless (p3 != MAP_FAILED);
                p = (uintptr_t) p3;
                fail_unless ((p & pagemask) == 0);
                munmap (p2, pagesize);
index 90c9e0b5e772639bd529ee38b3fbf518c83b19e2..4f965e2ebdb84e1d436d3886ac1e1d21b9c4dfbf 100644 (file)
@@ -54,6 +54,7 @@ disable bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
 disable bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
 disable bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 disable bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
+disable bdrv_set_locked(void *bs, int locked) "bs %p locked %d"
 
 # hw/virtio-blk.c
 disable virtio_blk_req_complete(void *req, int status) "req %p status %d"
@@ -234,27 +235,27 @@ disable grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable
 disable grlib_gptimer_restart(int id, uint32_t reload) "timer:%d reload val: 0x%x"
 disable grlib_gptimer_set_scaler(uint32_t scaler, uint32_t freq) "scaler:0x%x freq: 0x%x"
 disable grlib_gptimer_hit(int id) "timer:%d HIT"
-disable grlib_gptimer_readl(int id, const char *s, uint32_t val) "timer:%d %s 0x%x"
-disable grlib_gptimer_writel(int id, const char *s, uint32_t val) "timer:%d %s 0x%x"
-disable grlib_gptimer_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64""
+disable grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
+disable grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
 
 # hw/grlib_irqmp.c
 disable grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x\n"
 disable grlib_irqmp_ack(int intno) "interrupt:%d"
 disable grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
-disable grlib_irqmp_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64""
+disable grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64""
+disable grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
 
 # hw/grlib_apbuart.c
 disable grlib_apbuart_event(int event) "event:%d"
-disable grlib_apbuart_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64""
+disable grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
 
 # hw/leon3.c
 disable leon3_set_irq(int intno) "Set CPU IRQ %d"
 disable leon3_reset_irq(int intno) "Reset CPU IRQ %d"
 
 # spice-qemu-char.c
-disable spice_vmc_write(ssize_t out, int len) "spice wrottn %lu of requested %zd"
-disable spice_vmc_read(int bytes, int len) "spice read %lu of requested %zd"
+disable spice_vmc_write(ssize_t out, int len) "spice wrottn %zd of requested %d"
+disable spice_vmc_read(int bytes, int len) "spice read %d of requested %d"
 disable spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
 disable spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
 
@@ -286,3 +287,77 @@ disable lm32_uart_irq_state(int level) "irq state %d"
 
 # hw/lm32_sys.c
 disable lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+
+# hw/milkymist-ac97.c
+disable milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
+disable milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply"
+disable milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write"
+disable milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read"
+disable milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u"
+disable milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
+disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
+disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
+
+# hw/milkymist-hpdmc.c
+disable milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+
+# hw/milkymist-memcard.c
+disable milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+
+# hw/milkymist-minimac2.c
+disable milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
+disable milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
+disable milkymist_minimac2_tx_frame(uint32_t length) "length %u"
+disable milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u"
+disable milkymist_minimac2_drop_rx_frame(const void *buf) "buf %p"
+disable milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d"
+disable milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX"
+disable milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX"
+disable milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX"
+
+# hw/milkymist-pfpu.c
+disable milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x"
+disable milkymist_pfpu_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-softusb.c
+disable milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_softusb_mevt(uint8_t m) "m %d"
+disable milkymist_softusb_kevt(uint8_t m) "m %d"
+disable milkymist_softusb_mouse_event(int dx, int dy, int dz, int bs) "dx %d dy %d dz %d bs %02x"
+disable milkymist_softusb_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-sysctl.c
+disable milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_sysctl_icap_write(uint32_t value) "value %08x"
+disable milkymist_sysctl_start_timer0(void) "Start timer0"
+disable milkymist_sysctl_stop_timer0(void) "Stop timer0"
+disable milkymist_sysctl_start_timer1(void) "Start timer1"
+disable milkymist_sysctl_stop_timer1(void) "Stop timer1"
+disable milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0"
+disable milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1"
+
+# hw/milkymist-tmu2.c
+disable milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_tmu2_start(void) "Start TMU"
+disable milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
+
+# hw/milkymist-uart.c
+disable milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX"
+disable milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
+
+# hw/milkymist-vgafb.c
+disable milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
+disable milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
index efcfb9adcdc82fa6d1ef7969e11584c1956d3271..2ca190ca8fe8ab010200f7280dca0bbac20f5bb6 100644 (file)
@@ -112,8 +112,7 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
 /* The cpu state corresponding to 'searched_pc' is restored.
  */
 int cpu_restore_state(TranslationBlock *tb,
-                      CPUState *env, unsigned long searched_pc,
-                      void *puc)
+                      CPUState *env, unsigned long searched_pc)
 {
     TCGContext *s = &tcg_ctx;
     int j;
@@ -157,7 +156,7 @@ int cpu_restore_state(TranslationBlock *tb,
         j--;
     env->icount_decr.u16.low -= gen_opc_icount[j];
 
-    gen_pc_load(env, tb, searched_pc, j, puc);
+    restore_state_to_opc(env, tb, j);
 
 #ifdef CONFIG_PROFILER
     s->restore_time += profile_getclock() - ti;
index c5bb0a3705dec6d94eed5899e2dc955bab84bd01..dc5c3a1bc2c58a8df2b63e55e594a38e48c011d0 100644 (file)
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -812,6 +812,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     uint8_t data = 0;
     DisplayAllocator *da;
     const SDL_VideoInfo *vi;
+    char *filename;
 
 #if defined(__APPLE__)
     /* always use generic keymaps */
@@ -844,6 +845,18 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     vi = SDL_GetVideoInfo();
     host_format = *(vi->vfmt);
 
+    /* Load a 32x32x4 image. White pixels are transparent. */
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
+    if (filename) {
+        SDL_Surface *image = SDL_LoadBMP(filename);
+        if (image) {
+            uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255);
+            SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
+            SDL_WM_SetIcon(image, NULL);
+        }
+        qemu_free(filename);
+    }
+
     dcl = qemu_mallocz(sizeof(DisplayChangeListener));
     dcl->dpy_update = sdl_update;
     dcl->dpy_resize = sdl_resize;
index 2522936193b47e850aaa43ccaac1c367203f1f3e..87fdf35d3ea11d8cc8bdab7e37c6d4e4f6011990 100644 (file)
@@ -868,8 +868,8 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
     zstream->avail_in = vs->tight.tight.offset;
     zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
     zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
+    previous_out = zstream->avail_out;
     zstream->data_type = Z_BINARY;
-    previous_out = zstream->total_out;
 
     /* start encoding */
     if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
@@ -878,7 +878,8 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
     }
 
     vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
-    bytes = zstream->total_out - previous_out;
+    /* ...how much data has actually been produced by deflate() */
+    bytes = previous_out - zstream->avail_out;
 
     tight_send_compact_size(vs, bytes);
     vnc_write(vs, vs->tight.zlib.buffer, bytes);
index 3c6e6abf9482a5a9806ee15e19293c4623a4f15d..e32e4cd8a826262494df1dc0e03985f74231c481 100644 (file)
@@ -103,8 +103,8 @@ static int vnc_zlib_stop(VncState *vs)
     zstream->avail_in = vs->zlib.zlib.offset;
     zstream->next_out = vs->output.buffer + vs->output.offset;
     zstream->avail_out = vs->output.capacity - vs->output.offset;
+    previous_out = zstream->avail_out;
     zstream->data_type = Z_BINARY;
-    previous_out = zstream->total_out;
 
     // start encoding
     if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
@@ -113,7 +113,7 @@ static int vnc_zlib_stop(VncState *vs)
     }
 
     vs->output.offset = vs->output.capacity - zstream->avail_out;
-    return zstream->total_out - previous_out;
+    return previous_out - zstream->avail_out;
 }
 
 int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
index 55cb87edecad7e14a6f51f6815d8eb1921f378ec..df33cfe53c9dc92113c883a95f99d0a4d3e26e41 100644 (file)
@@ -202,6 +202,24 @@ static const name2keysym_t name2keysym[]={
 { "ydiaeresis",           0x0ff},
 {"EuroSign", 0x20ac},  /* XK_EuroSign */
 
+/* latin 2 - Polish national characters */
+{ "eogonek",              0x1ea},
+{ "Eogonek",              0x1ca},
+{ "aogonek",              0x1b1},
+{ "Aogonek",              0x1a1},
+{ "sacute",               0x1b6},
+{ "Sacute",               0x1a6},
+{ "lstroke",              0x1b3},
+{ "Lstroke",              0x1a3},
+{ "zabovedot",            0x1bf},
+{ "Zabovedot",            0x1af},
+{ "zacute",               0x1bc},
+{ "Zacute",               0x1ac},
+{ "cacute",               0x1e6},
+{ "Cacute",               0x1c6},
+{ "nacute",               0x1f1},
+{ "Nacute",               0x1d1},
+
     /* modifiers */
 {"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */
 {"Control_L", 0xffe3}, /* XK_Control_L */
index abcb60c6f1d63d26a5283778b1eee378fcaaa01f..50ccd489fecb829f6a410edb91886e927c7c4f05 100644 (file)
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -464,7 +464,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
                 printf("usb_host_scan: couldn't get device information for %s - %s\n",
                        devbuf, strerror(errno));
 
-            // XXX: might need to fixup endianess of word values before copying over
+            /* XXX: might need to fixup endianness of word values before copying over */
 
             vendor_id = dev_info.udi_vendorNo;
             product_id = dev_info.udi_productNo;
index 255009f53913c17a99426b83ea763d3d020e6ec0..1f33c2c230f6171cf98c42ab399b2ab093156e35 100644 (file)
@@ -107,7 +107,7 @@ enum {
 /*
  * Control transfer state.
  * Note that 'buffer' _must_ follow 'req' field because
- * we need contigious buffer when we submit control URB.
+ * we need contiguous buffer when we submit control URB.
  */
 struct ctrl_struct {
     uint16_t len;
@@ -344,6 +344,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
         for (interface = 0; interface < nb_interfaces; interface++) {
             ctrl.ioctl_code = USBDEVFS_DISCONNECT;
             ctrl.ifno = interface;
+            ctrl.data = 0;
             ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
             if (ret < 0 && errno != ENODATA) {
                 perror("USBDEVFS_DISCONNECT");
@@ -579,7 +580,7 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
     /*
      * Setup ctrl transfer.
      *
-     * s->ctrl is layed out such that data buffer immediately follows
+     * s->ctrl is laid out such that data buffer immediately follows
      * 'req' struct which is exactly what usbdevfs expects.
      */
     urb = &aurb->urb;
diff --git a/vl.c b/vl.c
index 192a240b52e3b3f9ee9bb0b457880519f60ff6e4..6b9a2f61e3a7752765ef21630736bd7d2746beb3 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -756,7 +756,7 @@ void add_boot_device_path(int32_t bootindex, DeviceState *dev,
 
 /*
  * This function returns null terminated string that consist of new line
- * separated device pathes.
+ * separated device paths.
  *
  * memory pointed by "size" is assigned total length of the array in bytes
  *
@@ -1022,68 +1022,6 @@ void pcmcia_info(Monitor *mon)
                        "Empty");
 }
 
-/***********************************************************/
-/* I/O handling */
-
-typedef struct IOHandlerRecord {
-    int fd;
-    IOCanReadHandler *fd_read_poll;
-    IOHandler *fd_read;
-    IOHandler *fd_write;
-    int deleted;
-    void *opaque;
-    /* temporary data */
-    struct pollfd *ufd;
-    QLIST_ENTRY(IOHandlerRecord) next;
-} IOHandlerRecord;
-
-static QLIST_HEAD(, IOHandlerRecord) io_handlers =
-    QLIST_HEAD_INITIALIZER(io_handlers);
-
-
-/* XXX: fd_read_poll should be suppressed, but an API change is
-   necessary in the character devices to suppress fd_can_read(). */
-int qemu_set_fd_handler2(int fd,
-                         IOCanReadHandler *fd_read_poll,
-                         IOHandler *fd_read,
-                         IOHandler *fd_write,
-                         void *opaque)
-{
-    IOHandlerRecord *ioh;
-
-    if (!fd_read && !fd_write) {
-        QLIST_FOREACH(ioh, &io_handlers, next) {
-            if (ioh->fd == fd) {
-                ioh->deleted = 1;
-                break;
-            }
-        }
-    } else {
-        QLIST_FOREACH(ioh, &io_handlers, next) {
-            if (ioh->fd == fd)
-                goto found;
-        }
-        ioh = qemu_mallocz(sizeof(IOHandlerRecord));
-        QLIST_INSERT_HEAD(&io_handlers, ioh, next);
-    found:
-        ioh->fd = fd;
-        ioh->fd_read_poll = fd_read_poll;
-        ioh->fd_read = fd_read;
-        ioh->fd_write = fd_write;
-        ioh->opaque = opaque;
-        ioh->deleted = 0;
-    }
-    return 0;
-}
-
-int qemu_set_fd_handler(int fd,
-                        IOHandler *fd_read,
-                        IOHandler *fd_write,
-                        void *opaque)
-{
-    return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
-}
-
 /***********************************************************/
 /* machine registration */
 
@@ -1231,8 +1169,15 @@ int qemu_shutdown_requested(void)
 void qemu_kill_report(void)
 {
     if (shutdown_signal != -1) {
-        fprintf(stderr, "Got signal %d from pid %d\n",
-                         shutdown_signal, shutdown_pid);
+        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
+             * avoiding printing an odd message in that case.
+             */
+            fputc('\n', stderr);
+        } else {
+            fprintf(stderr, " from pid %d\n", shutdown_pid);
+        }
         shutdown_signal = -1;
     }
 }
@@ -1343,7 +1288,6 @@ void qemu_system_vmstop_request(int reason)
 
 void main_loop_wait(int nonblocking)
 {
-    IOHandlerRecord *ioh;
     fd_set rfds, wfds, xfds;
     int ret, nfds;
     struct timeval tv;
@@ -1358,56 +1302,23 @@ void main_loop_wait(int nonblocking)
 
     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;
     FD_ZERO(&rfds);
     FD_ZERO(&wfds);
     FD_ZERO(&xfds);
-    QLIST_FOREACH(ioh, &io_handlers, next) {
-        if (ioh->deleted)
-            continue;
-        if (ioh->fd_read &&
-            (!ioh->fd_read_poll ||
-             ioh->fd_read_poll(ioh->opaque) != 0)) {
-            FD_SET(ioh->fd, &rfds);
-            if (ioh->fd > nfds)
-                nfds = ioh->fd;
-        }
-        if (ioh->fd_write) {
-            FD_SET(ioh->fd, &wfds);
-            if (ioh->fd > nfds)
-                nfds = ioh->fd;
-        }
-    }
-
-    tv.tv_sec = timeout / 1000;
-    tv.tv_usec = (timeout % 1000) * 1000;
-
+    qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
     slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
 
     qemu_mutex_unlock_iothread();
     ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
     qemu_mutex_lock_iothread();
-    if (ret > 0) {
-        IOHandlerRecord *pioh;
-
-        QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
-            if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
-                ioh->fd_read(ioh->opaque);
-            }
-            if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
-                ioh->fd_write(ioh->opaque);
-            }
-
-            /* Do this last in case read/write handlers marked it for deletion */
-            if (ioh->deleted) {
-                QLIST_REMOVE(ioh, next);
-                qemu_free(ioh);
-            }
-        }
-    }
 
+    qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
     slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
 
     qemu_run_all_timers();
@@ -1687,7 +1598,7 @@ static int balloon_parse(const char *arg)
             /* create empty opts */
             opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
         }
-        qemu_opt_set(opts, "driver", "virtio-balloon-pci");
+        qemu_opt_set(opts, "driver", "virtio-balloon");
         return 0;
     }
 
@@ -2191,7 +2102,9 @@ int main(int argc, char **argv, char **envp)
                           HD_OPTS);
                 break;
             case QEMU_OPTION_drive:
-                drive_def(optarg);
+                if (drive_def(optarg) == NULL) {
+                    exit(1);
+                }
                break;
             case QEMU_OPTION_set:
                 if (qemu_set_option(optarg) != 0)
@@ -2534,9 +2447,8 @@ int main(int argc, char **argv, char **envp)
                 }
                 break;
             case QEMU_OPTION_virtfs: {
-                char *arg_fsdev = NULL;
-                char *arg_9p = NULL;
-                int len = 0;
+                QemuOpts *fsdev;
+                QemuOpts *device;
 
                 olist = qemu_find_opts("virtfs");
                 if (!olist) {
@@ -2555,45 +2467,28 @@ int main(int argc, char **argv, char **envp)
                         qemu_opt_get(opts, "security_model") == NULL) {
                     fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
                             "security_model=[mapped|passthrough|none],"
-                            "mnt_tag=tag.\n");
+                            "mount_tag=tag.\n");
                     exit(1);
                 }
 
-                len = strlen(",id=,path=,security_model=");
-                len += strlen(qemu_opt_get(opts, "fstype"));
-                len += strlen(qemu_opt_get(opts, "mount_tag"));
-                len += strlen(qemu_opt_get(opts, "path"));
-                len += strlen(qemu_opt_get(opts, "security_model"));
-                arg_fsdev = qemu_malloc((len + 1) * sizeof(*arg_fsdev));
-
-                snprintf(arg_fsdev, (len + 1) * sizeof(*arg_fsdev),
-                         "%s,id=%s,path=%s,security_model=%s",
-                         qemu_opt_get(opts, "fstype"),
-                         qemu_opt_get(opts, "mount_tag"),
-                         qemu_opt_get(opts, "path"),
-                         qemu_opt_get(opts, "security_model"));
-
-                len = strlen("virtio-9p-pci,fsdev=,mount_tag=");
-                len += 2*strlen(qemu_opt_get(opts, "mount_tag"));
-                arg_9p = qemu_malloc((len + 1) * sizeof(*arg_9p));
-
-                snprintf(arg_9p, (len + 1) * sizeof(*arg_9p),
-                         "virtio-9p-pci,fsdev=%s,mount_tag=%s",
-                         qemu_opt_get(opts, "mount_tag"),
-                         qemu_opt_get(opts, "mount_tag"));
-
-                if (!qemu_opts_parse(qemu_find_opts("fsdev"), arg_fsdev, 1)) {
-                    fprintf(stderr, "parse error [fsdev]: %s\n", optarg);
+                fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
+                                         qemu_opt_get(opts, "mount_tag"), 1);
+                if (!fsdev) {
+                    fprintf(stderr, "duplicate fsdev id: %s\n",
+                            qemu_opt_get(opts, "mount_tag"));
                     exit(1);
                 }
-
-                if (!qemu_opts_parse(qemu_find_opts("device"), arg_9p, 1)) {
-                    fprintf(stderr, "parse error [device]: %s\n", optarg);
-                    exit(1);
-                }
-
-                qemu_free(arg_fsdev);
-                qemu_free(arg_9p);
+                qemu_opt_set(fsdev, "fstype", qemu_opt_get(opts, "fstype"));
+                qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
+                qemu_opt_set(fsdev, "security_model",
+                             qemu_opt_get(opts, "security_model"));
+
+                device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+                qemu_opt_set(device, "driver", "virtio-9p-pci");
+                qemu_opt_set(device, "fsdev",
+                             qemu_opt_get(opts, "mount_tag"));
+                qemu_opt_set(device, "mount_tag",
+                             qemu_opt_get(opts, "mount_tag"));
                 break;
             }
             case QEMU_OPTION_serial:
@@ -3148,9 +3043,6 @@ int main(int argc, char **argv, char **envp)
 
     cpu_synchronize_all_post_init();
 
-    /* must be after terminal init, SDL library changes signal handlers */
-    os_setup_signal_handling();
-
     set_numa_modes();
 
     current_machine = machine;
@@ -3206,6 +3098,9 @@ int main(int argc, char **argv, char **envp)
         break;
     }
 
+    /* must be after terminal init, SDL library changes signal handlers */
+    os_setup_signal_handling();
+
 #ifdef CONFIG_VNC
     /* init remote displays */
     if (vnc_display) {